From d365f5a82d7df9667ad7151213c606ba78bc3f3e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:05:33 +0000 Subject: [PATCH 001/191] Adding speculative global history, moving update to ROB, and replacing BTBHistory with FTQ --- src/include/simeng/BranchPredictor.hh | 7 +++ src/include/simeng/GenericPredictor.hh | 4 +- src/include/simeng/PerceptronPredictor.hh | 6 +- src/include/simeng/models/outoforder/Core.hh | 3 + src/include/simeng/pipeline/ExecuteUnit.hh | 7 +-- src/lib/GenericPredictor.cc | 29 +++++++-- src/lib/PerceptronPredictor.cc | 31 ++++++++-- src/lib/models/inorder/Core.cc | 2 +- src/lib/models/outoforder/Core.cc | 62 +++++++++++++++++++- src/lib/pipeline/DecodeUnit.cc | 7 ++- src/lib/pipeline/ExecuteUnit.cc | 9 +-- src/lib/pipeline/FetchUnit.cc | 1 + src/lib/pipeline/ReorderBuffer.cc | 6 ++ test/unit/MockBranchPredictor.hh | 1 + test/unit/pipeline/ExecuteUnitTest.cc | 2 +- 15 files changed, 145 insertions(+), 32 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 8e2ddd0797..1f58f5938f 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -60,6 +60,13 @@ class BranchPredictor { * via the instruction address. */ virtual void flush(uint64_t address) = 0; + + virtual void addToFTQ(uint64_t address) = 0; + + + uint64_t pre = 0; + uint64_t upd = 0; + uint64_t flu = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 28e7ccbaac..697e1dc5b1 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,6 +40,8 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + void addToFTQ(uint64_t address) override; + private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ uint8_t btbBits_; @@ -49,7 +51,7 @@ class GenericPredictor : public BranchPredictor { std::vector> btb_; /** The previous BTB index calculated for an address. */ - std::map btbHistory_; + std::deque> FTQ_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index b76e4dd7e4..348fe37f8d 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,6 +43,8 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + void addToFTQ(uint64_t address) override; + private: /** Returns the dot product of a perceptron and a history vector. Used to * determine a direction prediction */ @@ -59,8 +61,8 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** The previous hashed index for an address. */ - std::map btbHistory_; + /** Fetch Target Queue containing the address and previous global history state of branches that are currently unresolved */ + std::deque> FTQ_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ diff --git a/src/include/simeng/models/outoforder/Core.hh b/src/include/simeng/models/outoforder/Core.hh index 2b1b16f8a0..e7d2d5c40f 100644 --- a/src/include/simeng/models/outoforder/Core.hh +++ b/src/include/simeng/models/outoforder/Core.hh @@ -134,6 +134,9 @@ class Core : public simeng::Core { /** A pointer to the instruction responsible for generating the exception. */ std::shared_ptr exceptionGeneratingInstruction_; + + /** Reference to the current branch predictor */ + BranchPredictor& predictor_; }; } // namespace outoforder diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index 14d8b47e7c..a72de10850 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -33,8 +33,7 @@ class ExecuteUnit { std::function&)> handleLoad, std::function&)> handleStore, std::function&)> raiseException, - BranchPredictor& predictor, bool pipelined = true, - const std::vector& blockingGroups = {}); + bool pipelined = true, const std::vector& blockingGroups = {}); /** Tick the execute unit. Places incoming instructions into the pipeline and * executes an instruction that has reached the head of the pipeline, if @@ -91,10 +90,6 @@ class ExecuteUnit { /** A function handle called upon exception generation. */ std::function&)> raiseException_; - /** A reference to the branch predictor, for updating with prediction results. - */ - BranchPredictor& predictor_; - /** Whether this unit is pipelined, or if all instructions should stall until * complete. */ bool pipelined_; diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 7379c661af..ebafdb997e 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -23,7 +23,7 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) btb_ = std::vector>(1 << btbBits_, {satCntVal, 0}); // Alter globalHistoryLength_ value to better suit required format in update() - globalHistoryLength_ = (1 << globalHistoryLength_) - 1; + globalHistoryLength_ = (1 << (globalHistoryLength_ * 2)) - 1; } GenericPredictor::~GenericPredictor() { @@ -37,11 +37,11 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Get index via an XOR hash between the global history and the lower btbBits_ // bits of the instruction address uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; - btbHistory_[address] = hashedIndex; + FTQ_.emplace_back(address, hashedIndex); // Get prediction from BTB bool direction = - btb_[hashedIndex].first < (1 << (satCntBits_ - 1)) ? false : true; + btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; BranchPrediction prediction = {direction, target}; @@ -70,13 +70,19 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, } else if (type == BranchType::Conditional) { if (!prediction.taken) prediction.target = address + 4; } + + globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; + return prediction; } void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { + if (FTQ_.empty() || FTQ_.front().first != address) return; + // Get previous index calculated for the instruction address supplied - uint64_t hashedIndex = btbHistory_[address]; + uint64_t hashedIndex = FTQ_.front().second; + FTQ_.pop_front(); // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; @@ -89,8 +95,11 @@ void GenericPredictor::update(uint64_t address, bool taken, // Update BTB entry btb_[hashedIndex] = {satCntVal, targetAddress}; - // Update global history value with new direction - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; + + // Update global history if prediction was incorrect + // ToDo -- consider if need to replace history rather than just remove? + if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) globalHistory_ >>= 1; + return; } @@ -115,6 +124,14 @@ void GenericPredictor::flush(uint64_t address) { } rasHistory_.erase(it); } + + if (!FTQ_.empty()) FTQ_.pop_back(); + + globalHistory_ >>= 1; +} + +void GenericPredictor::addToFTQ(uint64_t address) { + FTQ_.emplace_back(address, globalHistory_); } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 8d1202f8d6..49a84d302f 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -38,7 +38,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - btbHistory_[address] = globalHistory_; + FTQ_.emplace_back(address, globalHistory_); // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -78,13 +78,23 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } else if (type == BranchType::Conditional) { if (!prediction.taken) prediction.target = address + 4; } + + // speculatively update global history + globalHistory_ = + ((globalHistory_ << 1) | prediction.taken) & ((1 << (globalHistoryLength_ * 2)) - 1); + + pre++; return prediction; } void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { + // Make sure there is FTQ info and it relates to the correct branch + if (FTQ_.empty() || FTQ_.front().first != address) return; // Work out hash index - uint64_t prevGlobalHistory = btbHistory_[address]; + uint64_t prevGlobalHistory = FTQ_.front().second; + FTQ_.pop_front(); + uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); @@ -118,8 +128,11 @@ void PerceptronPredictor::update(uint64_t address, bool taken, btb_[hashedIndex].first = perceptron; btb_[hashedIndex].second = targetAddress; - globalHistory_ = - ((globalHistory_ << 1) | taken) & ((1 << globalHistoryLength_) - 1); + // Update global history if prediction was incorrect + // ToDo -- consider if need to replace history rather than just remove? + if (directionPrediction != taken) globalHistory_ >>= 1; + + upd++;; return; } @@ -144,6 +157,16 @@ void PerceptronPredictor::flush(uint64_t address) { } rasHistory_.erase(it); } + + if (!FTQ_.empty()) FTQ_.pop_back(); + + // Roll back global history + globalHistory_ >>= 1; + flu++; +} + +void PerceptronPredictor::addToFTQ(uint64_t address) { + FTQ_.emplace_back(address, globalHistory_); } int64_t PerceptronPredictor::getDotProduct( diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index b196d2cf8c..de6878657c 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -31,7 +31,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, [this](auto instruction) { handleLoad(instruction); }, [this](auto instruction) { storeData(instruction); }, [this](auto instruction) { raiseException(instruction); }, - branchPredictor, false), + false), writebackUnit_(completionSlots_, registerFileSet_, [](auto insnId) {}) { // Query and apply initial state auto state = isa.getInitialState(); diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 4f7cf0f42d..e697778ae5 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -72,7 +72,8 @@ Core::Core(memory::MemoryInterface& instructionMemory, config["LSQ-L1-Interface"]["Permitted-Stores-Per-Cycle"] .as()), portAllocator_(portAllocator), - commitWidth_(config["Pipeline-Widths"]["Commit"].as()) { + commitWidth_(config["Pipeline-Widths"]["Commit"].as()), + predictor_(branchPredictor) { for (size_t i = 0; i < config["Execution-Units"].num_children(); i++) { // Create vector of blocking groups std::vector blockingGroups = {}; @@ -87,7 +88,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, }, [this](auto uop) { loadStoreQueue_.startLoad(uop); }, [this](auto uop) { loadStoreQueue_.supplyStoreData(uop); }, - [](auto uop) { uop->setCommitReady(); }, branchPredictor, + [](auto uop) { uop->setCommitReady(); }, config["Execution-Units"][i]["Pipelined"].as(), blockingGroups); } // Provide reservation size getter to A64FX port allocator @@ -236,6 +237,13 @@ std::map Core::getStats() const { std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; + std::cout << "_____BRANCH STATS_____" << std::endl + << "Predictions:\t\t" << predictor_.pre << std::endl + << "Updates: \t\t" << predictor_.upd << std::endl + << "Flushes: \t\t" << predictor_.flu << std::endl + << "Delta: \t\t\t" << ((int64_t)predictor_.pre - ((int64_t)predictor_.upd + (int64_t)predictor_.flu)) << std::endl + << std::endl << std::endl; + return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, @@ -263,9 +271,29 @@ void Core::raiseException(const std::shared_ptr& instruction) { } void Core::handleException() { + for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { + auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + } fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); + for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { + auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + uop = decodeToRenameBuffer_.getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + } decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -345,9 +373,29 @@ void Core::flushIfNeeded() { fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); + for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { + auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + } fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); + for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { + auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + uop = decodeToRenameBuffer_.getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + } decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -371,6 +419,16 @@ void Core::flushIfNeeded() { fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); + for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { + auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + } fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index cd152be942..647f24ec21 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -93,7 +93,12 @@ bool DecodeUnit::shouldFlush() const { return shouldFlush_; } uint64_t DecodeUnit::getFlushAddress() const { return pc_; } uint64_t DecodeUnit::getEarlyFlushes() const { return earlyFlushes_; } -void DecodeUnit::purgeFlushed() { microOps_.clear(); } +void DecodeUnit::purgeFlushed() { + while (!microOps_.empty()) { + if (microOps_.front()->isBranch()) predictor_.flush(microOps_.front()->getInstructionAddress()); + microOps_.pop_front(); + } +} } // namespace pipeline } // namespace simeng diff --git a/src/lib/pipeline/ExecuteUnit.cc b/src/lib/pipeline/ExecuteUnit.cc index c87c2e1845..b1b7d5fed7 100644 --- a/src/lib/pipeline/ExecuteUnit.cc +++ b/src/lib/pipeline/ExecuteUnit.cc @@ -13,15 +13,13 @@ ExecuteUnit::ExecuteUnit( std::function&)> handleLoad, std::function&)> handleStore, std::function&)> raiseException, - BranchPredictor& predictor, bool pipelined, - const std::vector& blockingGroups) + bool pipelined, const std::vector& blockingGroups) : input_(input), output_(output), forwardOperands_(forwardOperands), handleLoad_(handleLoad), handleStore_(handleStore), raiseException_(raiseException), - predictor_(predictor), pipelined_(pipelined), blockingGroups_(blockingGroups) {} @@ -140,11 +138,6 @@ void ExecuteUnit::execute(std::shared_ptr& uop) { if (uop->isBranch()) { pc_ = uop->getBranchAddress(); - - // Update branch predictor with branch results - predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), pc_, - uop->getBranchType()); - // Update the branch instruction counter branchesExecuted_++; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 553c8198f4..4d392ee388 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,6 +53,7 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress()); } // Cycle queue by moving front entry to back diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 32889bf93e..19a257aa7e 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -152,6 +152,12 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { 0}; } } + + // If it is a branch, now update the predictor (here to ensure order of updates is correct + if (uop->isBranch()) { + predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); + } + buffer_.pop_front(); } diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 05868a6fed..6e8fb36aaa 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -13,6 +13,7 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type)); MOCK_METHOD1(flush, void(uint64_t address)); + MOCK_METHOD1(addToFTQ, void(uint64_t address)); }; } // namespace simeng diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index 0f82593ff6..1c6664e384 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -35,7 +35,7 @@ class PipelineExecuteUnitTest : public testing::Test { [this](auto instruction) { executionHandlers.raiseException(instruction); }, - predictor, true, {3, 4, 5}), + true, {3, 4, 5}), uop(new MockInstruction), secondUop(new MockInstruction), thirdUop(new MockInstruction), From 524c48d581934c8c772ab2d3f57a66c7aa062427 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:12:25 +0000 Subject: [PATCH 002/191] Getting rid of print statements used to track down missing branches --- src/include/simeng/BranchPredictor.hh | 5 ----- src/lib/GenericPredictor.cc | 1 + src/lib/PerceptronPredictor.cc | 5 ++--- src/lib/models/outoforder/Core.cc | 7 ------- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 1f58f5938f..145f709f0f 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -62,11 +62,6 @@ class BranchPredictor { virtual void flush(uint64_t address) = 0; virtual void addToFTQ(uint64_t address) = 0; - - - uint64_t pre = 0; - uint64_t upd = 0; - uint64_t flu = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index ebafdb997e..aa00aded4b 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -30,6 +30,7 @@ GenericPredictor::~GenericPredictor() { btb_.clear(); ras_.clear(); rasHistory_.clear(); + FTQ_.clear(); } BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 49a84d302f..56f349e8a8 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -25,6 +25,8 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) PerceptronPredictor::~PerceptronPredictor() { ras_.clear(); rasHistory_.clear(); + std::cout << "___________REMAINING FTQ OF SIZE " << FTQ_.size() << std::endl; + FTQ_.clear(); } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, @@ -83,7 +85,6 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & ((1 << (globalHistoryLength_ * 2)) - 1); - pre++; return prediction; } @@ -132,7 +133,6 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // ToDo -- consider if need to replace history rather than just remove? if (directionPrediction != taken) globalHistory_ >>= 1; - upd++;; return; } @@ -162,7 +162,6 @@ void PerceptronPredictor::flush(uint64_t address) { // Roll back global history globalHistory_ >>= 1; - flu++; } void PerceptronPredictor::addToFTQ(uint64_t address) { diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index e697778ae5..f853e9efd3 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -237,13 +237,6 @@ std::map Core::getStats() const { std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; - std::cout << "_____BRANCH STATS_____" << std::endl - << "Predictions:\t\t" << predictor_.pre << std::endl - << "Updates: \t\t" << predictor_.upd << std::endl - << "Flushes: \t\t" << predictor_.flu << std::endl - << "Delta: \t\t\t" << ((int64_t)predictor_.pre - ((int64_t)predictor_.upd + (int64_t)predictor_.flu)) << std::endl - << std::endl << std::endl; - return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, From 15fe35d67e455d26b4bb6d7085845c80977e5735 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:16:38 +0000 Subject: [PATCH 003/191] Changing how globalHistory is updated in the event of a mispredicton --- src/lib/GenericPredictor.cc | 5 +++-- src/lib/PerceptronPredictor.cc | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index aa00aded4b..32f243fe06 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -98,8 +98,9 @@ void GenericPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect - // ToDo -- consider if need to replace history rather than just remove? - if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) globalHistory_ >>= 1; + if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { + globalHistory_ ^= (1 << FTQ_.size()); + } return; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 56f349e8a8..b119134c03 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -25,7 +25,6 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) PerceptronPredictor::~PerceptronPredictor() { ras_.clear(); rasHistory_.clear(); - std::cout << "___________REMAINING FTQ OF SIZE " << FTQ_.size() << std::endl; FTQ_.clear(); } @@ -130,8 +129,9 @@ void PerceptronPredictor::update(uint64_t address, bool taken, btb_[hashedIndex].second = targetAddress; // Update global history if prediction was incorrect - // ToDo -- consider if need to replace history rather than just remove? - if (directionPrediction != taken) globalHistory_ >>= 1; + if (directionPrediction != taken) { + globalHistory_ ^= (1 << FTQ_.size()); + } return; } From 0411a32edf99a9beda52614c862001cb00f97685 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:30:56 +0000 Subject: [PATCH 004/191] Clang format etc. --- src/include/simeng/PerceptronPredictor.hh | 3 ++- src/lib/GenericPredictor.cc | 19 ++++++++++++------- src/lib/PerceptronPredictor.cc | 20 +++++++++++--------- src/lib/models/inorder/Core.cc | 3 +-- src/lib/pipeline/FetchUnit.cc | 2 ++ src/lib/pipeline/ReorderBuffer.cc | 6 ++++-- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 348fe37f8d..42dd697ad6 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -61,7 +61,8 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** Fetch Target Queue containing the address and previous global history state of branches that are currently unresolved */ + /** Fetch Target Queue containing the address and previous global history + * state of branches that are currently unresolved */ std::deque> FTQ_; /** An n-bit history of previous branch directions where n is equal to diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 32f243fe06..2bf2257c20 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -38,11 +38,12 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Get index via an XOR hash between the global history and the lower btbBits_ // bits of the instruction address uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + + // Store the hashed index for correct hashing in update() FTQ_.emplace_back(address, hashedIndex); // Get prediction from BTB - bool direction = - btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); + bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; BranchPrediction prediction = {direction, target}; @@ -72,16 +73,19 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, if (!prediction.taken) prediction.target = address + 4; } - globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; + // Speculatively update the global history + globalHistory_ = + ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; return prediction; } void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { + // Sanity check to avoid segfault/wrong branch update if (FTQ_.empty() || FTQ_.front().first != address) return; - // Get previous index calculated for the instruction address supplied + // Get previous index calculated from the FTQ uint64_t hashedIndex = FTQ_.front().second; FTQ_.pop_front(); @@ -96,13 +100,12 @@ void GenericPredictor::update(uint64_t address, bool taken, // Update BTB entry btb_[hashedIndex] = {satCntVal, targetAddress}; - // Update global history if prediction was incorrect if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { + // Bit-flip the global history bit corresponding to this prediction + // We know how many predictions there have since been by the size of the FTQ globalHistory_ ^= (1 << FTQ_.size()); } - - return; } void GenericPredictor::flush(uint64_t address) { @@ -127,8 +130,10 @@ void GenericPredictor::flush(uint64_t address) { rasHistory_.erase(it); } + // If possible, pop instruction from FTQ if (!FTQ_.empty()) FTQ_.pop_back(); + // Roll back global history globalHistory_ >>= 1; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index b119134c03..e35d04c38b 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -81,20 +81,22 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } // speculatively update global history - globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & ((1 << (globalHistoryLength_ * 2)) - 1); + globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & + ((1 << (globalHistoryLength_ * 2)) - 1); return prediction; } void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Make sure there is FTQ info and it relates to the correct branch + // Sanity check to avoid segfault/wrong branch update if (FTQ_.empty() || FTQ_.front().first != address) return; - // Work out hash index + + // Get previous branch state from FTQ uint64_t prevGlobalHistory = FTQ_.front().second; FTQ_.pop_front(); + // Work out hashed index uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); @@ -129,11 +131,9 @@ void PerceptronPredictor::update(uint64_t address, bool taken, btb_[hashedIndex].second = targetAddress; // Update global history if prediction was incorrect - if (directionPrediction != taken) { - globalHistory_ ^= (1 << FTQ_.size()); - } - - return; + // Bit-flip the global history bit corresponding to this prediction + // We know how many predictions there have since been by the size of the FTQ + if (directionPrediction != taken) globalHistory_ ^= (1 << FTQ_.size()); } void PerceptronPredictor::flush(uint64_t address) { @@ -158,6 +158,7 @@ void PerceptronPredictor::flush(uint64_t address) { rasHistory_.erase(it); } + // If possible, pop instruction from FTQ if (!FTQ_.empty()) FTQ_.pop_back(); // Roll back global history @@ -165,6 +166,7 @@ void PerceptronPredictor::flush(uint64_t address) { } void PerceptronPredictor::addToFTQ(uint64_t address) { + // Add instruction to the FTQ in event of reused prediction FTQ_.emplace_back(address, globalHistory_); } diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index de6878657c..16b21d2a4d 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -30,8 +30,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, [this](auto regs, auto values) { forwardOperands(regs, values); }, [this](auto instruction) { handleLoad(instruction); }, [this](auto instruction) { storeData(instruction); }, - [this](auto instruction) { raiseException(instruction); }, - false), + [this](auto instruction) { raiseException(instruction); }, false), writebackUnit_(completionSlots_, registerFileSet_, [](auto insnId) {}) { // Query and apply initial state auto state = isa.getInitialState(); diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 4d392ee388..e3bd6e6fbe 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,6 +53,8 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + // Let the branch predictor know the prediction is being reused so that + // the FTQ can be kept up to date branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress()); } diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 19a257aa7e..4c89c30e66 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -153,9 +153,11 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { } } - // If it is a branch, now update the predictor (here to ensure order of updates is correct + // If it is a branch, now update the predictor (here to ensure order of + // updates is correct if (uop->isBranch()) { - predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); + predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType()); } buffer_.pop_front(); From 13fec7d23f2c5694db33deed547f6c69dd61d7b3 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:38:45 +0000 Subject: [PATCH 005/191] Adding to documentation --- docs/sphinx/developer/components/branchPred.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index ba91fe98d9..6466802080 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -3,7 +3,7 @@ Branch prediction SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredictor`` class to enable speculative execution. -Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, and ``flush`` provides optional algorithm specific flushing functionality. +Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, ``flush``, and ``addToFTQ``` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, ``flush`` provides optional algorithm specific flushing functionality, and ``addToFTQ`` adds an instruction to the predictor's Fetch Target Queue (FTQ) when a new prediction is not needed. The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: @@ -23,7 +23,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. + For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -41,7 +41,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. + For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. From 38be41ce14c6c0a97b5b52cbfc536c6e4ed97af9 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Sat, 24 Feb 2024 18:20:18 +0000 Subject: [PATCH 006/191] Fixing global history bug in generic predictor --- src/lib/GenericPredictor.cc | 3 +- src/lib/PerceptronPredictor.cc | 5 +- test/unit/GenericPredictorTest.cc | 91 ++++++++++++++++--------- test/unit/PerceptronPredictorTest.cc | 89 +++++++++++++++--------- test/unit/pipeline/ExecuteUnitTest.cc | 13 ---- test/unit/pipeline/RenameUnitTest.cc | 2 +- test/unit/pipeline/ReorderBufferTest.cc | 16 ++--- 7 files changed, 129 insertions(+), 90 deletions(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 2bf2257c20..0d3439cab3 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -138,7 +138,8 @@ void GenericPredictor::flush(uint64_t address) { } void GenericPredictor::addToFTQ(uint64_t address) { - FTQ_.emplace_back(address, globalHistory_); + uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + FTQ_.emplace_back(address, hashedIndex); } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index e35d04c38b..38d2c9ac4b 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -90,7 +90,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { // Sanity check to avoid segfault/wrong branch update - if (FTQ_.empty() || FTQ_.front().first != address) return; + //if (FTQ_.empty() || FTQ_.front().first != address) return; // Get previous branch state from FTQ uint64_t prevGlobalHistory = FTQ_.front().second; @@ -159,7 +159,8 @@ void PerceptronPredictor::flush(uint64_t address) { } // If possible, pop instruction from FTQ - if (!FTQ_.empty()) FTQ_.pop_back(); + // if (!FTQ_.empty()) FTQ_.pop_back(); + FTQ_.pop_back(); // Roll back global history globalHistory_ >>= 1; diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index c546157021..6e315babcd 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -82,15 +82,20 @@ TEST_F(GenericPredictorTest, RAS) { // correctly, when no address aliasing has occurred TEST_F(GenericPredictorTest, Hit) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 5, " "Saturating-Count-Bits: 2, Global-History-Length: 1, RAS-entries: 5, " "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); - predictor.update(0, false, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); @@ -101,60 +106,80 @@ TEST_F(GenericPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(GenericPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 5, " "Saturating-Count-Bits: 2, Global-History-Length: 5, RAS-entries: 5, " "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); - EXPECT_EQ(prediction.target, 0x23); + EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); - EXPECT_EQ(prediction.target, 0x23); + EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } // Test Flush of RAS functionality diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index b276b3795f..7ceb8a8bc6 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -72,14 +72,19 @@ TEST_F(PerceptronPredictorTest, RAS) { // branch correctly, when no address aliasing has occurred TEST_F(PerceptronPredictorTest, Hit) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 5, " "Global-History-Length: 1, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); - predictor.update(0, false, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); @@ -90,59 +95,79 @@ TEST_F(PerceptronPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(PerceptronPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 5, " "Global-History-Length: 5, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x1F, false, 0xAB, BranchType::Conditional); + predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); - EXPECT_EQ(prediction.target, 0x23); + EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, false, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } // Test Flush of RAS functionality diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index 1c6664e384..c324f60a9a 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -135,12 +135,6 @@ TEST_F(PipelineExecuteUnitTest, ExecuteBranch) { uop->setBranchResults(taken, pc); })); - // Check that the branch predictor was updated with the results - EXPECT_CALL(*uop, getBranchType()).Times(1); - EXPECT_CALL(predictor, - update(insnAddress, taken, pc, BranchType::Unconditional)) - .Times(1); - // Check that empty forwarding call is made EXPECT_CALL(executionHandlers, forwardOperands(IsEmpty(), IsEmpty())) .Times(1); @@ -288,13 +282,6 @@ TEST_F(PipelineExecuteUnitTest, mispredictedBranch) { uop->setBranchResults(taken, pc); })); - // Check that the branch predictor was updated with the results - EXPECT_CALL(*uop, getBranchType()).Times(1); - - EXPECT_CALL(predictor, - update(insnAddress, taken, pc, BranchType::Conditional)) - .Times(1); - // Check that empty forwarding call is made EXPECT_CALL(executionHandlers, forwardOperands(IsEmpty(), IsEmpty())) .Times(1); diff --git a/test/unit/pipeline/RenameUnitTest.cc b/test/unit/pipeline/RenameUnitTest.cc index 6b1dc640c5..3f3013adf6 100644 --- a/test/unit/pipeline/RenameUnitTest.cc +++ b/test/unit/pipeline/RenameUnitTest.cc @@ -427,7 +427,7 @@ TEST_F(RenameUnitTest, serializedDest) { EXPECT_CALL(*uop2, getDestinationRegisters()).Times(1); EXPECT_CALL(*uop2, isLoad()).WillOnce(Return(false)); EXPECT_CALL(*uop2, isStoreAddress()).WillOnce(Return(false)); - EXPECT_CALL(*uop2, isBranch()).WillOnce(Return(false)); + EXPECT_CALL(*uop2, isBranch()).Times(2).WillRepeatedly(Return(false)); rob.commit(1); EXPECT_EQ(rob.size(), 0); diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index abc33d871a..0a5429bba1 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -365,26 +365,26 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Fourth pass through ROB -- seen count = 3; exceeds detection theshold, // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -397,26 +397,26 @@ TEST_F(ReorderBufferTest, branch) { // Re-do loop detecition // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Fourth pass through ROB -- seen count = 3; exceeds detection theshold, // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); } From 40aabe4cb1f4fd57e61199a81488665a63e712c8 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:55:05 +0000 Subject: [PATCH 007/191] Fixing unit test failures resulting from changes to BP structure --- src/include/simeng/BranchPredictor.hh | 2 +- src/include/simeng/GenericPredictor.hh | 2 +- src/include/simeng/PerceptronPredictor.hh | 4 +- src/lib/GenericPredictor.cc | 11 +-- src/lib/PerceptronPredictor.cc | 9 ++- src/lib/pipeline/FetchUnit.cc | 3 +- test/unit/GenericPredictorTest.cc | 84 +++++++++++++++++------ test/unit/MockBranchPredictor.hh | 2 +- test/unit/PerceptronPredictorTest.cc | 84 +++++++++++++++++------ 9 files changed, 145 insertions(+), 56 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 145f709f0f..4446f46bf5 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -61,7 +61,7 @@ class BranchPredictor { */ virtual void flush(uint64_t address) = 0; - virtual void addToFTQ(uint64_t address) = 0; + virtual void addToFTQ(uint64_t address, bool taken) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 697e1dc5b1..f4774cda08 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,7 +40,7 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - void addToFTQ(uint64_t address) override; + void addToFTQ(uint64_t address, bool taken) override; private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 42dd697ad6..e256c19bcf 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,7 +43,7 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - void addToFTQ(uint64_t address) override; + void addToFTQ(uint64_t address, bool taken) override; private: /** Returns the dot product of a perceptron and a history vector. Used to @@ -72,6 +72,8 @@ class PerceptronPredictor : public BranchPredictor { /** The number of previous branch directions recorded globally. */ uint64_t globalHistoryLength_; + uint64_t globalHistoryMask_; + /** The magnitude of the dot product of the perceptron and the global history, * below which the perceptron's weight must be updated */ uint64_t trainingThreshold_; diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 0d3439cab3..8b2f4b2035 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -37,7 +37,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { // Get index via an XOR hash between the global history and the lower btbBits_ // bits of the instruction address - uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); // Store the hashed index for correct hashing in update() FTQ_.emplace_back(address, hashedIndex); @@ -104,7 +104,7 @@ void GenericPredictor::update(uint64_t address, bool taken, if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << FTQ_.size()); + globalHistory_ ^= (1 << (FTQ_.size() - 1)); } } @@ -137,9 +137,12 @@ void GenericPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void GenericPredictor::addToFTQ(uint64_t address) { - uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; +void GenericPredictor::addToFTQ(uint64_t address, bool taken) { + // Make the hashed index and add it to the FTQ + uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); FTQ_.emplace_back(address, hashedIndex); + // Speculatively update the global history + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 38d2c9ac4b..e9b43a0630 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -20,6 +20,8 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Set up training threshold according to empirically determined formula trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); + + globalHistoryMask_ = (globalHistoryLength_ * 2) - 1; } PerceptronPredictor::~PerceptronPredictor() { @@ -82,7 +84,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // speculatively update global history globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & - ((1 << (globalHistoryLength_ * 2)) - 1); + globalHistoryMask_; return prediction; } @@ -133,7 +135,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (directionPrediction != taken) globalHistory_ ^= (1 << FTQ_.size()); + if (directionPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size() - 1)); } void PerceptronPredictor::flush(uint64_t address) { @@ -166,9 +168,10 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void PerceptronPredictor::addToFTQ(uint64_t address) { +void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction FTQ_.emplace_back(address, globalHistory_); + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } int64_t PerceptronPredictor::getDotProduct( diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index e3bd6e6fbe..678ec4c748 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -55,7 +55,8 @@ void FetchUnit::tick() { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Let the branch predictor know the prediction is being reused so that // the FTQ can be kept up to date - branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress()); + branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchPrediction().taken); } // Cycle queue by moving front entry to back diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 6e315babcd..0f85658e52 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -106,20 +106,30 @@ TEST_F(GenericPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(GenericPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 5, " - "Saturating-Count-Bits: 2, Global-History-Length: 5, RAS-entries: 5, " + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 10, " + "Saturating-Count-Bits: 2, Global-History-Length: 10, RAS-entries: 5, " "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -129,16 +139,26 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); @@ -147,15 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -165,16 +195,26 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 6e8fb36aaa..a6db5caceb 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -13,7 +13,7 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type)); MOCK_METHOD1(flush, void(uint64_t address)); - MOCK_METHOD1(addToFTQ, void(uint64_t address)); + MOCK_METHOD2(addToFTQ, void(uint64_t address, bool taken)); }; } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 7ceb8a8bc6..ff05f51701 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -95,19 +95,29 @@ TEST_F(PerceptronPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(PerceptronPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 5, " - "Global-History-Length: 5, RAS-entries: 5}}"); + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 10, " + "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -117,15 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -135,15 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -153,15 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); From a30a254ea1cdba71e2ffce9ccae12269abfc2f2f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:53:27 +0000 Subject: [PATCH 008/191] Getting rid of redundant info in the FTQ --- src/include/simeng/GenericPredictor.hh | 2 +- src/include/simeng/PerceptronPredictor.hh | 2 +- src/lib/GenericPredictor.cc | 9 +++------ src/lib/PerceptronPredictor.cc | 9 +++------ 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index f4774cda08..c46c35e851 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -51,7 +51,7 @@ class GenericPredictor : public BranchPredictor { std::vector> btb_; /** The previous BTB index calculated for an address. */ - std::deque> FTQ_; + std::deque FTQ_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index e256c19bcf..bb7026f15f 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -63,7 +63,7 @@ class PerceptronPredictor : public BranchPredictor { /** Fetch Target Queue containing the address and previous global history * state of branches that are currently unresolved */ - std::deque> FTQ_; + std::deque FTQ_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 8b2f4b2035..dc59765dab 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -40,7 +40,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); // Store the hashed index for correct hashing in update() - FTQ_.emplace_back(address, hashedIndex); + FTQ_.emplace_back(hashedIndex); // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); @@ -82,11 +82,8 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Sanity check to avoid segfault/wrong branch update - if (FTQ_.empty() || FTQ_.front().first != address) return; - // Get previous index calculated from the FTQ - uint64_t hashedIndex = FTQ_.front().second; + uint64_t hashedIndex = FTQ_.front(); FTQ_.pop_front(); // Calculate 2-bit saturating counter value @@ -140,7 +137,7 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - FTQ_.emplace_back(address, hashedIndex); + FTQ_.emplace_back(hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index e9b43a0630..aba19704ff 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -41,7 +41,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - FTQ_.emplace_back(address, globalHistory_); + FTQ_.emplace_back(globalHistory_); // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -91,11 +91,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Sanity check to avoid segfault/wrong branch update - //if (FTQ_.empty() || FTQ_.front().first != address) return; - // Get previous branch state from FTQ - uint64_t prevGlobalHistory = FTQ_.front().second; + uint64_t prevGlobalHistory = FTQ_.front(); FTQ_.pop_front(); // Work out hashed index @@ -170,7 +167,7 @@ void PerceptronPredictor::flush(uint64_t address) { void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction - FTQ_.emplace_back(address, globalHistory_); + FTQ_.emplace_back(globalHistory_); globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } From 2ba15c4be13ff5027071f7da8d585293c4907c08 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:59:35 +0000 Subject: [PATCH 009/191] Clang Format --- src/lib/PerceptronPredictor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index aba19704ff..035c2edc61 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -83,8 +83,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } // speculatively update global history - globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & - globalHistoryMask_; + globalHistory_ = + ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; return prediction; } From 162a800d7aa9bfb6a24f446f20990de8674a8517 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:44:31 +0000 Subject: [PATCH 010/191] Adding new test for speculative global history updates --- src/include/simeng/GenericPredictor.hh | 5 ++- src/include/simeng/PerceptronPredictor.hh | 6 +-- src/lib/GenericPredictor.cc | 19 ++++----- src/lib/PerceptronPredictor.cc | 19 ++++----- test/unit/GenericPredictorTest.cc | 48 +++++++++++++++++++++++ test/unit/PerceptronPredictorTest.cc | 47 ++++++++++++++++++++++ 6 files changed, 121 insertions(+), 23 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index c46c35e851..f0d587cc37 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -50,8 +50,9 @@ class GenericPredictor : public BranchPredictor { * counter and a branch target. */ std::vector> btb_; - /** The previous BTB index calculated for an address. */ - std::deque FTQ_; + /** Fetch Target Queue containing the direction prediction and previous global + * history state of branches that are currently unresolved */ + std::deque> FTQ_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index bb7026f15f..1734d1aee7 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -61,9 +61,9 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** Fetch Target Queue containing the address and previous global history - * state of branches that are currently unresolved */ - std::deque FTQ_; + /** Fetch Target Queue containing the direction prediction and previous global + * history state of branches that are currently unresolved */ + std::deque> FTQ_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index dc59765dab..273afeb92f 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -39,9 +39,6 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // bits of the instruction address uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - // Store the hashed index for correct hashing in update() - FTQ_.emplace_back(hashedIndex); - // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = @@ -73,6 +70,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, if (!prediction.taken) prediction.target = address + 4; } + // Store the hashed index for correct hashing in update() + FTQ_.emplace_back(prediction.taken, hashedIndex); + // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; @@ -82,8 +82,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Get previous index calculated from the FTQ - uint64_t hashedIndex = FTQ_.front(); + // Get previous prediciton and index calculated from the FTQ + bool prevPrediction = FTQ_.front().first; + uint64_t hashedIndex = FTQ_.front().second; FTQ_.pop_front(); // Calculate 2-bit saturating counter value @@ -98,10 +99,10 @@ void GenericPredictor::update(uint64_t address, bool taken, btb_[hashedIndex] = {satCntVal, targetAddress}; // Update global history if prediction was incorrect - if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { + if (prevPrediction != taken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << (FTQ_.size() - 1)); + globalHistory_ ^= (1 << (FTQ_.size())); } } @@ -128,7 +129,7 @@ void GenericPredictor::flush(uint64_t address) { } // If possible, pop instruction from FTQ - if (!FTQ_.empty()) FTQ_.pop_back(); + FTQ_.pop_back(); // Roll back global history globalHistory_ >>= 1; @@ -137,7 +138,7 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - FTQ_.emplace_back(hashedIndex); + FTQ_.emplace_back(taken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 035c2edc61..9d1142fc7b 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -38,11 +38,6 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - // Store the global history for correct hashing in update() -- - // needs to be global history and not the hashed index as hashing loses - // information at longer global history lengths - FTQ_.emplace_back(globalHistory_); - // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -82,6 +77,11 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, if (!prediction.taken) prediction.target = address + 4; } + // Store the global history for correct hashing in update() -- + // needs to be global history and not the hashed index as hashing loses + // information at longer global history lengths + FTQ_.emplace_back(prediction.taken, globalHistory_); + // speculatively update global history globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; @@ -91,8 +91,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Get previous branch state from FTQ - uint64_t prevGlobalHistory = FTQ_.front(); + // Get previous branch state and prediction from FTQ + bool prevPrediction = FTQ_.front().first; + uint64_t prevGlobalHistory = FTQ_.front().second; FTQ_.pop_front(); // Work out hashed index @@ -132,7 +133,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (directionPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size() - 1)); + if (prevPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -167,7 +168,7 @@ void PerceptronPredictor::flush(uint64_t address) { void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction - FTQ_.emplace_back(globalHistory_); + FTQ_.emplace_back(taken, globalHistory_); globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 0f85658e52..9fb10ba168 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -260,4 +260,52 @@ TEST_F(GenericPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } +// Test that update correctly corrects the speculatively updated gloabl history +TEST_F(GenericPredictorTest, speculativeGlobalHistory) { + simeng::config::SimInfo::addToConfig( + "{Branch-Predictor: {BTB-Tag-Bits: 2, Saturating-Count-Bits: 6, " + "Global-History-Length: 6, RAS-entries: 10, Fallback-Static-Predictor: " + "Always-Taken}}"); + auto predictor = simeng::GenericPredictor(); + // spool up a global history to set the target address + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure default behaviour for first encounter + auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0x4); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + + // recreate this global history but with incorrect predictions + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure default behaviour for first encounter + prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0xAB); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); +} + } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index ff05f51701..70485355dd 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -247,4 +247,51 @@ TEST_F(PerceptronPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } +// Test that update correctly corrects the speculatively updated gloabl history +TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { + simeng::config::SimInfo::addToConfig( + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 2, " + "Global-History-Length: 6, RAS-entries: 5}}"); + auto predictor = simeng::PerceptronPredictor(); + // spool up a global history to set the target address + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure default behaviour for first encounter + auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0x4); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + + // recreate this global history but with incorrect predictions + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure prediction is correct with new target address + prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0xAB); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); +} + } // namespace simeng From da59fdfba2ff242a73c7c3c94c4ac50773a9a6db Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:52:45 +0000 Subject: [PATCH 011/191] Addressing superficial comments on PR --- src/include/simeng/BranchPredictor.hh | 1 + src/include/simeng/GenericPredictor.hh | 3 ++- src/include/simeng/PerceptronPredictor.hh | 5 ++++- src/lib/GenericPredictor.cc | 22 +++++++++++----------- src/lib/PerceptronPredictor.cc | 18 ++++++++---------- src/lib/pipeline/ReorderBuffer.cc | 2 +- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 4446f46bf5..39d2c2f2d5 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -61,6 +61,7 @@ class BranchPredictor { */ virtual void flush(uint64_t address) = 0; + /** Adds instruction to the Fetch Target Queue without making a new prediction */ virtual void addToFTQ(uint64_t address, bool taken) = 0; }; diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index f0d587cc37..009a6fbd3b 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,6 +40,7 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + /** Adds instruction to the Fetch Target Queue without making a new prediction */ void addToFTQ(uint64_t address, bool taken) override; private: @@ -52,7 +53,7 @@ class GenericPredictor : public BranchPredictor { /** Fetch Target Queue containing the direction prediction and previous global * history state of branches that are currently unresolved */ - std::deque> FTQ_; + std::deque> ftq_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 1734d1aee7..29cf3eb460 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,6 +43,7 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + /** Adds instruction to the Fetch Target Queue without making a new prediction */ void addToFTQ(uint64_t address, bool taken) override; private: @@ -63,7 +64,7 @@ class PerceptronPredictor : public BranchPredictor { /** Fetch Target Queue containing the direction prediction and previous global * history state of branches that are currently unresolved */ - std::deque> FTQ_; + std::deque> ftq_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ @@ -72,6 +73,8 @@ class PerceptronPredictor : public BranchPredictor { /** The number of previous branch directions recorded globally. */ uint64_t globalHistoryLength_; + /** A bit mask for truncating the global history to the correct size. + * Stored as a member variable to avoid duplicative calculation */ uint64_t globalHistoryMask_; /** The magnitude of the dot product of the perceptron and the global history, diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 273afeb92f..a7d154d49e 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -30,14 +30,14 @@ GenericPredictor::~GenericPredictor() { btb_.clear(); ras_.clear(); rasHistory_.clear(); - FTQ_.clear(); + ftq_.clear(); } BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { - // Get index via an XOR hash between the global history and the lower btbBits_ - // bits of the instruction address - uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); + // Get index via an XOR hash between the global history and the instruction address. + // This hash is then ANDed to keep it within bounds of the btb + uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); @@ -71,7 +71,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, } // Store the hashed index for correct hashing in update() - FTQ_.emplace_back(prediction.taken, hashedIndex); + ftq_.emplace_back(prediction.taken, hashedIndex); // Speculatively update the global history globalHistory_ = @@ -83,9 +83,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { // Get previous prediciton and index calculated from the FTQ - bool prevPrediction = FTQ_.front().first; - uint64_t hashedIndex = FTQ_.front().second; - FTQ_.pop_front(); + bool prevPrediction = ftq_.front().first; + uint64_t hashedIndex = ftq_.front().second; + ftq_.pop_front(); // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; @@ -102,7 +102,7 @@ void GenericPredictor::update(uint64_t address, bool taken, if (prevPrediction != taken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << (FTQ_.size())); + globalHistory_ ^= (1 << (ftq_.size())); } } @@ -129,7 +129,7 @@ void GenericPredictor::flush(uint64_t address) { } // If possible, pop instruction from FTQ - FTQ_.pop_back(); + ftq_.pop_back(); // Roll back global history globalHistory_ >>= 1; @@ -138,7 +138,7 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - FTQ_.emplace_back(taken, hashedIndex); + ftq_.emplace_back(taken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 9d1142fc7b..6b1be4d407 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -27,7 +27,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) PerceptronPredictor::~PerceptronPredictor() { ras_.clear(); rasHistory_.clear(); - FTQ_.clear(); + ftq_.clear(); } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, @@ -80,7 +80,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - FTQ_.emplace_back(prediction.taken, globalHistory_); + ftq_.emplace_back(prediction.taken, globalHistory_); // speculatively update global history globalHistory_ = @@ -92,9 +92,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { // Get previous branch state and prediction from FTQ - bool prevPrediction = FTQ_.front().first; - uint64_t prevGlobalHistory = FTQ_.front().second; - FTQ_.pop_front(); + bool prevPrediction = ftq_.front().first; + uint64_t prevGlobalHistory = ftq_.front().second; + ftq_.pop_front(); // Work out hashed index uint64_t hashedIndex = @@ -133,7 +133,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (prevPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size())); + if (prevPrediction != taken) globalHistory_ ^= (1 << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -158,9 +158,7 @@ void PerceptronPredictor::flush(uint64_t address) { rasHistory_.erase(it); } - // If possible, pop instruction from FTQ - // if (!FTQ_.empty()) FTQ_.pop_back(); - FTQ_.pop_back(); + ftq_.pop_back(); // Roll back global history globalHistory_ >>= 1; @@ -168,7 +166,7 @@ void PerceptronPredictor::flush(uint64_t address) { void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction - FTQ_.emplace_back(taken, globalHistory_); + ftq_.emplace_back(taken, globalHistory_); globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 4c89c30e66..8ec673ace1 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -154,7 +154,7 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { } // If it is a branch, now update the predictor (here to ensure order of - // updates is correct + // updates is correct) if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); From 11d483feec24d668c013239da195b5c2ed95777f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:19:17 +0000 Subject: [PATCH 012/191] Adding EXPECT_CALL for branch predictor in reorderBufferTest.cc --- test/unit/pipeline/ReorderBufferTest.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 0a5429bba1..d0a7b9bf2f 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -366,18 +366,24 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -385,6 +391,8 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -398,18 +406,24 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -417,6 +431,8 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); } From 1b2202ce874237f2ec5aca3d89a9bbb7abf71b48 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:55:52 +0000 Subject: [PATCH 013/191] Moving branch statistic collectiong to Reorder buffer and updating tests accordingly --- src/include/simeng/pipeline/ExecuteUnit.hh | 12 ------------ src/include/simeng/pipeline/ReorderBuffer.hh | 12 ++++++++++++ src/lib/models/inorder/Core.cc | 19 ++++++++++--------- src/lib/models/outoforder/Core.cc | 9 ++------- src/lib/pipeline/ExecuteUnit.cc | 11 ----------- src/lib/pipeline/ReorderBuffer.cc | 11 +++++++++++ test/unit/pipeline/ExecuteUnitTest.cc | 4 ---- test/unit/pipeline/ReorderBufferTest.cc | 5 +++++ 8 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index a72de10850..c803476873 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -55,12 +55,6 @@ class ExecuteUnit { * stall, if applicable. */ void purgeFlushed(); - /** Retrieve the number of branch instructions that have been executed. */ - uint64_t getBranchExecutedCount() const; - - /** Retrieve the number of branch mispredictions. */ - uint64_t getBranchMispredictedCount() const; - /** Retrieve the number of active execution cycles. */ uint64_t getCycles() const; @@ -124,12 +118,6 @@ class ExecuteUnit { /** The cycle this unit will become unstalled. */ uint64_t stallUntil_ = 0; - /** The number of branch instructions that were executed. */ - uint64_t branchesExecuted_ = 0; - - /** The number of branch mispredictions that were observed. */ - uint64_t branchMispredicts_ = 0; - /** The number of active execution cycles that were observed. */ uint64_t cycles_ = 0; }; diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index 278a0174ca..abe4a94b34 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -85,6 +85,12 @@ class ReorderBuffer { /** Get the number of speculated loads which violated load-store ordering. */ uint64_t getViolatingLoadsCount() const; + /** Retrieve the number of branch instructions that have been executed. */ + uint64_t getBranchExecutedCount() const; + + /** Retrieve the number of branch mispredictions. */ + uint64_t getBranchMispredictedCount() const; + private: /** A reference to the register alias table. */ RegisterAliasTable& rat_; @@ -144,6 +150,12 @@ class ReorderBuffer { /** The number of speculative loads which violated load-store ordering. */ uint64_t loadViolations_ = 0; + + /** The number of branch instructions that were executed. */ + uint64_t branchesExecuted_ = 0; + + /** The number of branch mispredictions that were observed. */ + uint64_t branchMispredicts_ = 0; }; } // namespace pipeline diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 16b21d2a4d..09a5602977 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -148,21 +148,22 @@ std::map Core::getStats() const { ipcStr << std::setprecision(2) << ipc; // Sum up the branch stats reported across the execution units. - uint64_t totalBranchesExecuted = 0; - uint64_t totalBranchMispredicts = 0; - totalBranchesExecuted += executeUnit_.getBranchExecutedCount(); - totalBranchMispredicts += executeUnit_.getBranchMispredictedCount(); - auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesExecuted); +// uint64_t totalBranchesExecuted = 0; +// uint64_t totalBranchMispredicts = 0; +// totalBranchesExecuted += executeUnit_.getBranchExecutedCount(); +// totalBranchMispredicts += executeUnit_.getBranchMispredictedCount(); +// auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / +// static_cast(totalBranchesExecuted); std::ostringstream branchMissRateStr; - branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; +// branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; + branchMissRateStr << "Not yet implemented for in order"; return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, {"flushes", std::to_string(flushes_)}, - {"branch.executed", std::to_string(totalBranchesExecuted)}, - {"branch.mispredict", std::to_string(totalBranchMispredicts)}, +// {"branch.executed", std::to_string(totalBranchesExecuted)}, +// {"branch.mispredict", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}}; } diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index f853e9efd3..0d39a8b936 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,14 +224,9 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = 0; - uint64_t totalBranchMispredicts = 0; + uint64_t totalBranchesExecuted = reorderBuffer_.getBranchExecutedCount(); + uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); - // Sum up the branch stats reported across the execution units. - for (auto& eu : executionUnits_) { - totalBranchesExecuted += eu.getBranchExecutedCount(); - totalBranchMispredicts += eu.getBranchMispredictedCount(); - } auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / static_cast(totalBranchesExecuted); std::ostringstream branchMissRateStr; diff --git a/src/lib/pipeline/ExecuteUnit.cc b/src/lib/pipeline/ExecuteUnit.cc index b1b7d5fed7..28a04dde28 100644 --- a/src/lib/pipeline/ExecuteUnit.cc +++ b/src/lib/pipeline/ExecuteUnit.cc @@ -138,15 +138,11 @@ void ExecuteUnit::execute(std::shared_ptr& uop) { if (uop->isBranch()) { pc_ = uop->getBranchAddress(); - // Update the branch instruction counter - branchesExecuted_++; if (uop->wasBranchMispredicted()) { // Misprediction; flush the pipeline shouldFlush_ = true; flushAfter_ = uop->getInstructionId(); - // Update the branch misprediction counter - branchMispredicts_++; } } @@ -208,13 +204,6 @@ void ExecuteUnit::purgeFlushed() { } } -uint64_t ExecuteUnit::getBranchExecutedCount() const { - return branchesExecuted_; -} -uint64_t ExecuteUnit::getBranchMispredictedCount() const { - return branchMispredicts_; -} - uint64_t ExecuteUnit::getCycles() const { return cycles_; } bool ExecuteUnit::isEmpty() const { diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 8ec673ace1..2b15fcd414 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -158,6 +158,10 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); + // Update the branch instruction counter + branchesExecuted_++; + // Update the branch misprediction counter + if (uop->wasBranchMispredicted()) branchMispredicts_++; } buffer_.pop_front(); @@ -214,5 +218,12 @@ uint64_t ReorderBuffer::getViolatingLoadsCount() const { return loadViolations_; } +uint64_t ReorderBuffer::getBranchExecutedCount() const { + return branchesExecuted_; +} +uint64_t ReorderBuffer::getBranchMispredictedCount() const { + return branchMispredicts_; +} + } // namespace pipeline } // namespace simeng diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index c324f60a9a..3665628b8c 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -146,8 +146,6 @@ TEST_F(PipelineExecuteUnitTest, ExecuteBranch) { EXPECT_EQ(executeUnit.shouldFlush(), false); EXPECT_EQ(output.getTailSlots()[0].get(), uop); - EXPECT_EQ(executeUnit.getBranchExecutedCount(), 1); - EXPECT_EQ(executeUnit.getBranchMispredictedCount(), 0); } // Test that an instruction that already encountered an exception will raise it @@ -293,8 +291,6 @@ TEST_F(PipelineExecuteUnitTest, mispredictedBranch) { EXPECT_EQ(executeUnit.shouldFlush(), true); EXPECT_EQ(output.getTailSlots()[0].get(), uop); - EXPECT_EQ(executeUnit.getBranchExecutedCount(), 1); - EXPECT_EQ(executeUnit.getBranchMispredictedCount(), 1); EXPECT_EQ(executeUnit.getFlushAddress(), pc); EXPECT_EQ(executeUnit.getFlushInsnId(), insnID); } diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index d0a7b9bf2f..be9c4086a7 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -361,6 +361,7 @@ TEST_F(ReorderBufferTest, branch) { uopPtr->setInstructionId(0); uopPtr->setInstructionAddress(insnAddr); uopPtr->setBranchPrediction(pred); + uop->setExecuted(true); uopPtr->setCommitReady(); // First pass through ROB -- seen count reset to 0 as new branch @@ -435,6 +436,10 @@ TEST_F(ReorderBufferTest, branch) { uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); + + // Check that branch metrics have been correctly collected + EXPECT_EQ(reorderBuffer.getBranchExecutedCount(), 8); + EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); } // Tests that only those destination registers which have been renamed are From 409d627fe3d74d910b207a4c3c560672b713f01f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:12:10 +0000 Subject: [PATCH 014/191] Removing BP stats from in-order core getstats --- src/lib/models/inorder/Core.cc | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 09a5602977..373529e695 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -147,24 +147,10 @@ std::map Core::getStats() const { std::ostringstream ipcStr; ipcStr << std::setprecision(2) << ipc; - // Sum up the branch stats reported across the execution units. -// uint64_t totalBranchesExecuted = 0; -// uint64_t totalBranchMispredicts = 0; -// totalBranchesExecuted += executeUnit_.getBranchExecutedCount(); -// totalBranchMispredicts += executeUnit_.getBranchMispredictedCount(); -// auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / -// static_cast(totalBranchesExecuted); - std::ostringstream branchMissRateStr; -// branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; - branchMissRateStr << "Not yet implemented for in order"; - return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, - {"flushes", std::to_string(flushes_)}, -// {"branch.executed", std::to_string(totalBranchesExecuted)}, -// {"branch.mispredict", std::to_string(totalBranchMispredicts)}, - {"branch.missrate", branchMissRateStr.str()}}; + {"flushes", std::to_string(flushes_)}; } void Core::raiseException(const std::shared_ptr& instruction) { From b9bb4f4ee22c23c1633b389ee6adfd302276b64c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:20:21 +0000 Subject: [PATCH 015/191] Moving branch prediction stat collection to fetch unit to better align with branch metrics reported by PMU events in A64FX --- src/include/simeng/pipeline/FetchUnit.hh | 6 ++++++ src/include/simeng/pipeline/ReorderBuffer.hh | 6 ------ src/lib/models/inorder/Core.cc | 2 +- src/lib/models/outoforder/Core.cc | 2 +- src/lib/pipeline/FetchUnit.cc | 6 ++++++ src/lib/pipeline/ReorderBuffer.cc | 6 ------ test/unit/pipeline/ReorderBufferTest.cc | 3 +-- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index 09e8bb31f6..0b16316888 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -69,6 +69,9 @@ class FetchUnit { /** Clear the loop buffer. */ void flushLoopBuffer(); + /** Retrieve the number of branch instructions that have been executed. */ + uint64_t getBranchExecutedCount() const; + private: /** An output buffer connecting this unit to the decode unit. */ PipelineBuffer& output_; @@ -118,6 +121,9 @@ class FetchUnit { /** The amount of data currently in the fetch buffer. */ uint16_t bufferedBytes_ = 0; + /** The number of branch instructions that were executed. */ + uint64_t branchesExecuted_ = 0; + /** Let the following PipelineFetchUnitTest derived classes be a friend of * this class to allow proper testing of 'tick' function. */ friend class PipelineFetchUnitTest_invalidMinBytesAtEndOfBuffer_Test; diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index abe4a94b34..64a32ce78b 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -85,9 +85,6 @@ class ReorderBuffer { /** Get the number of speculated loads which violated load-store ordering. */ uint64_t getViolatingLoadsCount() const; - /** Retrieve the number of branch instructions that have been executed. */ - uint64_t getBranchExecutedCount() const; - /** Retrieve the number of branch mispredictions. */ uint64_t getBranchMispredictedCount() const; @@ -151,9 +148,6 @@ class ReorderBuffer { /** The number of speculative loads which violated load-store ordering. */ uint64_t loadViolations_ = 0; - /** The number of branch instructions that were executed. */ - uint64_t branchesExecuted_ = 0; - /** The number of branch mispredictions that were observed. */ uint64_t branchMispredicts_ = 0; }; diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 373529e695..add307f714 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -150,7 +150,7 @@ std::map Core::getStats() const { return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, - {"flushes", std::to_string(flushes_)}; + {"flushes", std::to_string(flushes_)}}; } void Core::raiseException(const std::shared_ptr& instruction) { diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 0d39a8b936..a3bc30dc46 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,7 +224,7 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = reorderBuffer_.getBranchExecutedCount(); + uint64_t totalBranchesExecuted = fetchUnit_.getBranchExecutedCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 678ec4c748..48439f30f9 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -57,6 +57,7 @@ void FetchUnit::tick() { // the FTQ can be kept up to date branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchPrediction().taken); + branchesExecuted_++; } // Cycle queue by moving front entry to back @@ -151,6 +152,7 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { prediction = branchPredictor_.predict(pc_, macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); + branchesExecuted_++; macroOp[0]->setBranchPrediction(prediction); } @@ -275,5 +277,9 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } +uint64_t FetchUnit::getBranchExecutedCount() const { + return branchesExecuted_; +} + } // namespace pipeline } // namespace simeng diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 2b15fcd414..47b231e866 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -158,8 +158,6 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); - // Update the branch instruction counter - branchesExecuted_++; // Update the branch misprediction counter if (uop->wasBranchMispredicted()) branchMispredicts_++; } @@ -217,10 +215,6 @@ uint64_t ReorderBuffer::getInstructionsCommittedCount() const { uint64_t ReorderBuffer::getViolatingLoadsCount() const { return loadViolations_; } - -uint64_t ReorderBuffer::getBranchExecutedCount() const { - return branchesExecuted_; -} uint64_t ReorderBuffer::getBranchMispredictedCount() const { return branchMispredicts_; } diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index be9c4086a7..23960d058a 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -437,8 +437,7 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); - // Check that branch metrics have been correctly collected - EXPECT_EQ(reorderBuffer.getBranchExecutedCount(), 8); + // Check that branch misprediction metrics have been correctly collected EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); } From 300ea414083f98eb02ba487fb5df119a3cc7a739 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:20:50 +0000 Subject: [PATCH 016/191] Fixing typo --- test/unit/pipeline/ReorderBufferTest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 23960d058a..aa59fe0448 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -428,7 +428,7 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); - // Fourth pass through ROB -- seen count = 3; exceeds detection theshold, + // Fourth pass through ROB -- seen count = 3; exceeds detection threshold, // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); From 4377e7271a0b97b43900f3606f3d5b6eeeb3a389 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:48:32 +0000 Subject: [PATCH 017/191] Clang format --- src/include/simeng/BranchPredictor.hh | 3 ++- src/include/simeng/GenericPredictor.hh | 3 ++- src/include/simeng/PerceptronPredictor.hh | 3 ++- src/lib/GenericPredictor.cc | 7 ++++--- src/lib/pipeline/DecodeUnit.cc | 3 ++- src/lib/pipeline/FetchUnit.cc | 4 +--- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 39d2c2f2d5..eac6e5aaa0 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -61,7 +61,8 @@ class BranchPredictor { */ virtual void flush(uint64_t address) = 0; - /** Adds instruction to the Fetch Target Queue without making a new prediction */ + /** Adds instruction to the Fetch Target Queue without making a new prediction + */ virtual void addToFTQ(uint64_t address, bool taken) = 0; }; diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 009a6fbd3b..cb34e30ef5 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,7 +40,8 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction */ + /** Adds instruction to the Fetch Target Queue without making a new prediction + */ void addToFTQ(uint64_t address, bool taken) override; private: diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 29cf3eb460..9fd040fa8e 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,7 +43,8 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction */ + /** Adds instruction to the Fetch Target Queue without making a new prediction + */ void addToFTQ(uint64_t address, bool taken) override; private: diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index a7d154d49e..ad28c13378 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -35,9 +35,10 @@ GenericPredictor::~GenericPredictor() { BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { - // Get index via an XOR hash between the global history and the instruction address. - // This hash is then ANDed to keep it within bounds of the btb - uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + // Get index via an XOR hash between the global history and the instruction + // address. This hash is then ANDed to keep it within bounds of the btb + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 647f24ec21..4c557bfd56 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -95,7 +95,8 @@ uint64_t DecodeUnit::getEarlyFlushes() const { return earlyFlushes_; } void DecodeUnit::purgeFlushed() { while (!microOps_.empty()) { - if (microOps_.front()->isBranch()) predictor_.flush(microOps_.front()->getInstructionAddress()); + if (microOps_.front()->isBranch()) + predictor_.flush(microOps_.front()->getInstructionAddress()); microOps_.pop_front(); } } diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 48439f30f9..73a4bdab6b 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -277,9 +277,7 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } -uint64_t FetchUnit::getBranchExecutedCount() const { - return branchesExecuted_; -} +uint64_t FetchUnit::getBranchExecutedCount() const { return branchesExecuted_; } } // namespace pipeline } // namespace simeng From 16ec8acd2283c21cd0de85ee9502f4e515ba2e01 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:18:49 +0100 Subject: [PATCH 018/191] Adding ftq description in the BP docs --- docs/sphinx/developer/components/branchPred.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 6466802080..8331b0c9bc 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,6 +17,8 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottow of the queue on ``update`` and ``flush``. + Generic Predictor ----------------- From d7937e41640f29ec6faf4f84b7ac90af004caa16 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:23:00 +0100 Subject: [PATCH 019/191] Attending to Generic Predictor comments --- src/lib/GenericPredictor.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index ad28c13378..d0c23737db 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -36,7 +36,9 @@ GenericPredictor::~GenericPredictor() { BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { // Get index via an XOR hash between the global history and the instruction - // address. This hash is then ANDed to keep it within bounds of the btb + // address. This hash is then ANDed to keep it within bounds of the btb. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in a 64 bit ISA. uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); @@ -83,7 +85,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Get previous prediciton and index calculated from the FTQ + // Get previous prediction and index calculated from the FTQ bool prevPrediction = ftq_.front().first; uint64_t hashedIndex = ftq_.front().second; ftq_.pop_front(); @@ -138,7 +140,8 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ - uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); + uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) + - 1); ftq_.emplace_back(taken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; From a0d933a5175109812e4d7cf5151d6c03118b1d31 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:25:09 +0100 Subject: [PATCH 020/191] Docs typo fixed --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 8331b0c9bc..e2ff1d1ec1 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,7 +17,7 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottow of the queue on ``update`` and ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottom of the queue on ``update`` and from the top of the queue on ``flush``. Generic Predictor ----------------- From 4a120abea2e218442128274de7632a2296c0b7f7 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:40:33 +0100 Subject: [PATCH 021/191] Adding buffer check comment --- src/lib/models/outoforder/Core.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index a3bc30dc46..667d89ce0c 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -259,6 +259,8 @@ void Core::raiseException(const std::shared_ptr& instruction) { } void Core::handleException() { + // Check the buffer entries to see if they are branch instructions. If so, + // flush them from the BP for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; if (!macroOp.empty() && macroOp[0]->isBranch()) { From e673ddcdc7d1b133d6b1456234d5e76929e6930d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:43:05 +0100 Subject: [PATCH 022/191] Fixing typo --- test/unit/GenericPredictorTest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 9fb10ba168..2fe34f48a3 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -260,7 +260,7 @@ TEST_F(GenericPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } -// Test that update correctly corrects the speculatively updated gloabl history +// Test that update correctly corrects the speculatively updated global history TEST_F(GenericPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( "{Branch-Predictor: {BTB-Tag-Bits: 2, Saturating-Count-Bits: 6, " From 97c50b5574678668ca01ccd964c8d6b27d09db93 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:04:22 +0100 Subject: [PATCH 023/191] Updating comment re shifting the address to get the hashed index --- src/lib/GenericPredictor.cc | 2 +- src/lib/PerceptronPredictor.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index d0c23737db..0f0d1deec9 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -38,7 +38,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these - // are always 0 in a 64 bit ISA. + // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 6b1be4d407..9acd49a4d8 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -35,6 +35,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Get the hashed index for the prediction table. XOR the global history with // the non-zero bits of the address, and then keep only the btbBits_ bits of // the output to keep it in bounds of the prediction table. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); From 97bac68771cbf628ae9578ca9b463360e2294975 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:25:34 +0100 Subject: [PATCH 024/191] Adding comment re multiplying global history length by two --- src/lib/GenericPredictor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 0f0d1deec9..f9565a7687 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -23,6 +23,9 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) btb_ = std::vector>(1 << btbBits_, {satCntVal, 0}); // Alter globalHistoryLength_ value to better suit required format in update() + // Multiply original globalHistoryLength_ by two so that extra branch + // outcomes are stored to allow rolling back the speculatively updated + // global history in the event of a misprediction. globalHistoryLength_ = (1 << (globalHistoryLength_ * 2)) - 1; } From 01be4a5689713b348ecdc9139705b2c00fdb1972 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:29:39 +0100 Subject: [PATCH 025/191] Renaming getBranchExecutedCount to getBranchFetchedCount --- src/include/simeng/pipeline/FetchUnit.hh | 4 ++-- src/lib/models/outoforder/Core.cc | 2 +- src/lib/pipeline/FetchUnit.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index 0b16316888..c5a7383b4f 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -69,8 +69,8 @@ class FetchUnit { /** Clear the loop buffer. */ void flushLoopBuffer(); - /** Retrieve the number of branch instructions that have been executed. */ - uint64_t getBranchExecutedCount() const; + /** Retrieve the number of branch instructions that have been fetched. */ + uint64_t getBranchFetchedCount() const; private: /** An output buffer connecting this unit to the decode unit. */ diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 667d89ce0c..eb4bf41bcc 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,7 +224,7 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = fetchUnit_.getBranchExecutedCount(); + uint64_t totalBranchesExecuted = fetchUnit_.getBranchFetchedCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 73a4bdab6b..419accce76 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -277,7 +277,7 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } -uint64_t FetchUnit::getBranchExecutedCount() const { return branchesExecuted_; } +uint64_t FetchUnit::getBranchFetchedCount() const { return branchesExecuted_; } } // namespace pipeline } // namespace simeng From 9d8702ca607c821f8c0d2a89b679f4779db448f2 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:56:24 +0100 Subject: [PATCH 026/191] Adding globalHistoryMask_ variable to genericPredictor --- src/include/simeng/GenericPredictor.hh | 4 ++++ src/lib/GenericPredictor.cc | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index cb34e30ef5..24013efb85 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -66,6 +66,10 @@ class GenericPredictor : public BranchPredictor { /** The number of previous branch directions recorded globally. */ uint16_t globalHistoryLength_; + /** A bit mask for truncating the global history to the correct size. + * Stored as a member variable to avoid duplicative calculation */ + uint64_t globalHistoryMask_; + /** A return address stack. */ std::deque ras_; diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index f9565a7687..06875a51c5 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -26,7 +26,7 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // Multiply original globalHistoryLength_ by two so that extra branch // outcomes are stored to allow rolling back the speculatively updated // global history in the event of a misprediction. - globalHistoryLength_ = (1 << (globalHistoryLength_ * 2)) - 1; + globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; } GenericPredictor::~GenericPredictor() { @@ -81,7 +81,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Speculatively update the global history globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; + ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; return prediction; } @@ -147,7 +147,7 @@ void GenericPredictor::addToFTQ(uint64_t address, bool taken) { - 1); ftq_.emplace_back(taken, hashedIndex); // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } } // namespace simeng From 67ff81e90218be7f3276ef8b6a8fa79a6d3212ef Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:03:19 +0100 Subject: [PATCH 027/191] Adding more detail to virtual flush and update functions re order of calls --- src/include/simeng/BranchPredictor.hh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index eac6e5aaa0..1b62beea98 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -52,13 +52,16 @@ class BranchPredictor { int64_t knownOffset) = 0; /** Provide branch results to update the prediction model for the specified - * instruction address. */ + * instruction address. Update must be called on instructions in program + * order */ virtual void update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) = 0; /** Provides flushing behaviour for the implemented branch prediction schemes - * via the instruction address. - */ + * via the instruction address. Branches must be flushed in reverse + * program order (though, if a block of n instructions is being flushed at + * once, the exact order that the individual instructions within this block + * are flushed does not matter so long as they are all flushed) */ virtual void flush(uint64_t address) = 0; /** Adds instruction to the Fetch Target Queue without making a new prediction From 364f22d21aafa9c61f09b4982090a4b704204538 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:07:29 +0100 Subject: [PATCH 028/191] reversing order of purge flush from decodeUnit --- src/lib/pipeline/DecodeUnit.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 4c557bfd56..8748690488 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -95,9 +95,9 @@ uint64_t DecodeUnit::getEarlyFlushes() const { return earlyFlushes_; } void DecodeUnit::purgeFlushed() { while (!microOps_.empty()) { - if (microOps_.front()->isBranch()) - predictor_.flush(microOps_.front()->getInstructionAddress()); - microOps_.pop_front(); + if (microOps_.back()->isBranch()) + predictor_.flush(microOps_.back()->getInstructionAddress()); + microOps_.pop_back(); } } From 5a4e71c918a4181a4bc876f7b73a5bacbb507b96 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:52:16 +0100 Subject: [PATCH 029/191] Moving buffer branch flush functionality from core.cc to PipelineBuffer.hh --- src/include/simeng/pipeline/PipelineBuffer.hh | 28 +++++++++++++++++++ src/lib/models/outoforder/Core.cc | 22 ++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index 6e128ae684..b65d21c61a 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,6 +4,8 @@ #include #include +#include "simeng/BranchPredictor.hh" + namespace simeng { namespace pipeline { @@ -73,6 +75,32 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } + void flushBranchMicroOps(BranchPredictor& branchPredictor) { + for (size_t slot = 0; slot < width; slot++) { + auto& uop = getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + branchPredictor.flush(uop->getInstructionAddress()); + } + uop = getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + branchPredictor.flush(uop->getInstructionAddress()); + } + } + } + + void flushBranchMacroOps(BranchPredictor& branchPredictor) { + for (size_t slot = 0; slot < width; slot++) { + auto& macroOp = getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + branchPredictor.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + branchPredictor.flush(macroOp[0]->getInstructionAddress()); + } + } + } + private: /** The width of each row of slots. */ uint16_t width; diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index eb4bf41bcc..2cb1b28be4 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -261,29 +261,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check the buffer entries to see if they are branch instructions. If so, // flush them from the BP - for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { - auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - } + fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { - auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - uop = decodeToRenameBuffer_.getHeadSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - } + decodeToRenameBuffer_.flushBranchMicroOps(predictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); From b37e00a1ca6f51855c2afcdff3026276b5cb3a85 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:06:51 +0100 Subject: [PATCH 030/191] rebase --- .../developer/arch/supported/aarch64.rst | 4 +- .../developer/components/branchPred.rst | 8 +-- .../developer/components/coreinstance.rst | 2 +- .../components/pipeline/components.rst | 2 +- .../developer/components/pipeline/units.rst | 10 ++-- src/include/simeng/AlwaysNotTakenPredictor.hh | 6 +- src/include/simeng/BranchPredictor.hh | 14 ++--- src/include/simeng/GenericPredictor.hh | 4 +- src/include/simeng/Instruction.hh | 8 +-- src/include/simeng/PerceptronPredictor.hh | 4 +- .../arch/aarch64/helpers/conditional.hh | 4 +- src/include/simeng/config/yaml/ryml.hh | 20 +++---- src/lib/GenericPredictor.cc | 32 +++++------ src/lib/PerceptronPredictor.cc | 26 +++++---- src/lib/arch/aarch64/Instruction.cc | 4 +- src/lib/arch/riscv/Instruction.cc | 4 +- src/lib/pipeline/FetchUnit.cc | 12 ++-- test/unit/GenericPredictorTest.cc | 54 +++++++++--------- test/unit/PerceptronPredictorTest.cc | 56 ++++++++++--------- test/unit/aarch64/InstructionTest.cc | 12 ++-- test/unit/pipeline/FetchUnitTest.cc | 8 +-- test/unit/riscv/InstructionTest.cc | 12 ++-- 22 files changed, 155 insertions(+), 151 deletions(-) diff --git a/docs/sphinx/developer/arch/supported/aarch64.rst b/docs/sphinx/developer/arch/supported/aarch64.rst index 092264e991..6df0028e48 100644 --- a/docs/sphinx/developer/arch/supported/aarch64.rst +++ b/docs/sphinx/developer/arch/supported/aarch64.rst @@ -55,12 +55,12 @@ Additional information The ``FP`` primary identifier is a placeholder to denote both the ``SCALAR`` and ``VECTOR`` primary identifiers such that, amongst the other combinations, ``FP_SIMPLE_ARTH`` expands to be ``SCALAR_SIMPLE_ARTH`` and ``VECTOR_SIMPLE_ARTH``. In some cases it was unnecessary and inconvenient to separate ``SCALAR`` and ``VECTOR`` operations within configuration options, therefore, this instruction group option was provided to solve the issue. -When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is taken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. +When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is isTaken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. Instruction Splitting ********************* -Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is taken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: +Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is isTaken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: - Load pair for X/W/S/D/Q registers. diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index e2ff1d1ec1..b6a58d091a 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -30,13 +30,13 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. Static Prediction - Based on the chosen static prediction method of "always taken" or "always not taken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of taken or not-taken respectively. + Based on the chosen static prediction method of "always isTaken" or "always not isTaken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of isTaken or not-isTaken respectively. Perceptron Predictor -------------------- @@ -48,9 +48,9 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. - The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not taken if this is negative, or taken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. + The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not isTaken if this is negative, or isTaken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. \ No newline at end of file diff --git a/docs/sphinx/developer/components/coreinstance.rst b/docs/sphinx/developer/components/coreinstance.rst index 8b9e99a449..89b6247db4 100644 --- a/docs/sphinx/developer/components/coreinstance.rst +++ b/docs/sphinx/developer/components/coreinstance.rst @@ -3,7 +3,7 @@ Core Instance The ``CoreInstance`` component supplies the functionality for instantiating all simulation objects and linking them together. -The standard process taken to create an instance of the modelled core is as follows: +The standard process isTaken to create an instance of the modelled core is as follows: Process the config file Either the passed configuration file path, or default configuration string, is used to generate the model configuration class. All subsequent parameterised instantiations of simulation objects utilise this configuration class. diff --git a/docs/sphinx/developer/components/pipeline/components.rst b/docs/sphinx/developer/components/pipeline/components.rst index ab62a6b919..f74d5e892e 100644 --- a/docs/sphinx/developer/components/pipeline/components.rst +++ b/docs/sphinx/developer/components/pipeline/components.rst @@ -69,7 +69,7 @@ Once a completion slot is available, the load will be executed, the results broa Stores ****** -As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is taken from the ``storeQueue_`` entry. +As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is isTaken from the ``storeQueue_`` entry. The generation of store instruction write requests are carried out after its commitment. The reasoning for this design decision is as followed. With SimEng supporting speculative execution, processed store instruction may come from an incorrectly speculated branch direction and will inevitably be removed from the pipeline. Therefore, it is important to ensure any write requests are valid, concerning speculative execution, as the performance cost of reversing a completed write request is high. diff --git a/docs/sphinx/developer/components/pipeline/units.rst b/docs/sphinx/developer/components/pipeline/units.rst index 52358f4658..922b24f5a6 100644 --- a/docs/sphinx/developer/components/pipeline/units.rst +++ b/docs/sphinx/developer/components/pipeline/units.rst @@ -23,7 +23,7 @@ Behaviour The fetch unit fetches memory in discrete boundary-aligned blocks, according to the current program counter (PC); this is to prevent the fetched block overlapping an inaccessible or unmapped memory region that may result in the request incorrectly responding with a fault despite the validity of the initial region. -Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a taken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. +Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a isTaken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. This standard process of pre-decoding, predicting, and updating the PC continues until one of the following occurs: @@ -32,7 +32,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues The maximum number of fetched macro-ops is reached The current block is saved and processing resumes in the next cycle. - A branch is predicted as taken + A branch is predicted as isTaken A block of memory from the new address may be requested, and processing will resume once the data is available. The fetched memory block is exhausted @@ -43,7 +43,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues Loop Buffer *********** -Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is taken and increases the throughput of the fetch unit. +Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is isTaken and increases the throughput of the fetch unit. Each entry of the loop buffer is the encoding of the Macro-Op. Therefore, when supplying an instruction from the loop buffer, the pre-decoding step must still be performed. This was required to avoid any issues with multiple instantiations of the same instruction editing each others class members. @@ -59,7 +59,7 @@ FILLING The branch representing the loop has been found and the buffer is being filled until it is seen again. SUPPLYING - The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is taken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. + The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is isTaken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. The detection of a loop and the branch which represents it comes from the ROB. More information can be found :ref:`here `. @@ -81,7 +81,7 @@ Behaviour Each cycle, the decode unit will read macro-ops from the input buffer, and split them into a stream of ``Instruction`` objects or micro-ops. These ``Instruction`` objects are passed into an internal buffer. -Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a taken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. +Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a isTaken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. The cycle ends when all ``Instruction`` objects in the internal buffer have been processed, or a misprediction is identified and all remaining ``Instruction`` objects are flushed. diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/AlwaysNotTakenPredictor.hh index 7ec8027d4b..fc91e6d9ca 100644 --- a/src/include/simeng/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/AlwaysNotTakenPredictor.hh @@ -4,12 +4,12 @@ namespace simeng { -/** An "Always Not Taken" branch predictor; predicts all branches as not taken. +/** An "Always Not Taken" branch predictor; predicts all branches as not isTaken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will - * always predict not taken. */ + * always predict not isTaken. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset) override; @@ -19,7 +19,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { BranchType type) override; /** Provide flush logic for branch prediction scheme. As there's no flush - * logic for an always taken predictor, this does nothing. */ + * logic for an always isTaken predictor, this does nothing. */ void flush(uint64_t address) override; }; diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 1b62beea98..c4da8e1ff9 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -17,16 +17,16 @@ enum class BranchType { /** A branch result prediction for an instruction. */ struct BranchPrediction { - /** Whether the branch will be taken. */ - bool taken; + /** Whether the branch will be isTaken. */ + bool isTaken; - /** The branch instruction's target address. If `taken = false`, the value + /** The branch instruction's target address. If `isTaken = false`, the value * will be ignored. */ uint64_t target; /** Check for equality of two branch predictions . */ bool operator==(const BranchPrediction& other) { - if ((taken == other.taken) && (target == other.target)) + if ((isTaken == other.isTaken) && (target == other.target)) return true; else return false; @@ -34,7 +34,7 @@ struct BranchPrediction { /** Check for inequality of two branch predictions . */ bool operator!=(const BranchPrediction& other) { - if ((taken != other.taken) || (target != other.target)) + if ((isTaken != other.isTaken) || (target != other.target)) return true; else return false; @@ -54,7 +54,7 @@ class BranchPredictor { /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program * order */ - virtual void update(uint64_t address, bool taken, uint64_t targetAddress, + virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) = 0; /** Provides flushing behaviour for the implemented branch prediction schemes @@ -66,7 +66,7 @@ class BranchPredictor { /** Adds instruction to the Fetch Target Queue without making a new prediction */ - virtual void addToFTQ(uint64_t address, bool taken) = 0; + virtual void addToFTQ(uint64_t address, bool isTaken) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 24013efb85..7690c11b33 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -34,7 +34,7 @@ class GenericPredictor : public BranchPredictor { /** Updates appropriate predictor model objects based on the address and * outcome of the branch instruction. */ - void update(uint64_t address, bool taken, uint64_t targetAddress, + void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; /** Provides RAS rewinding behaviour. */ @@ -42,7 +42,7 @@ class GenericPredictor : public BranchPredictor { /** Adds instruction to the Fetch Target Queue without making a new prediction */ - void addToFTQ(uint64_t address, bool taken) override; + void addToFTQ(uint64_t address, bool isTaken) override; private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 9a126460de..8ce445402b 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -147,16 +147,16 @@ class Instruction { /** Retrieve branch address. */ uint64_t getBranchAddress() const { return branchAddress_; } - /** Was the branch taken? */ + /** Was the branch isTaken? */ bool wasBranchTaken() const { return branchTaken_; } /** Check for misprediction. */ bool wasBranchMispredicted() const { assert(executed_ && "Branch misprediction check requires instruction to have executed"); - // Flag as mispredicted if taken state was wrongly predicted, or taken and + // Flag as mispredicted if isTaken state was wrongly predicted, or isTaken and // predicted target is wrong - return (branchTaken_ != prediction_.taken || + return (branchTaken_ != prediction_.isTaken || (prediction_.target != branchAddress_)); } @@ -289,7 +289,7 @@ class Instruction { /** A branching address calculated by this instruction during execution. */ uint64_t branchAddress_ = 0; - /** Was the branch taken? */ + /** Was the branch isTaken? */ bool branchTaken_ = false; /** What type of branch this instruction is. */ diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 9fd040fa8e..9236e9e01e 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -37,7 +37,7 @@ class PerceptronPredictor : public BranchPredictor { /** Updates appropriate predictor model objects based on the address and * outcome of the branch instruction. */ - void update(uint64_t address, bool taken, uint64_t targetAddress, + void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; /** Provides RAS rewinding behaviour. */ @@ -45,7 +45,7 @@ class PerceptronPredictor : public BranchPredictor { /** Adds instruction to the Fetch Target Queue without making a new prediction */ - void addToFTQ(uint64_t address, bool taken) override; + void addToFTQ(uint64_t address, bool isTaken) override; private: /** Returns the dot product of a perceptron and a history vector. Used to diff --git a/src/include/simeng/arch/aarch64/helpers/conditional.hh b/src/include/simeng/arch/aarch64/helpers/conditional.hh index e541eb276a..2b3ea1b9c3 100644 --- a/src/include/simeng/arch/aarch64/helpers/conditional.hh +++ b/src/include/simeng/arch/aarch64/helpers/conditional.hh @@ -56,7 +56,7 @@ uint8_t ccmp_reg(srcValContainer& sourceValues, /** Helper function for instructions with the format `cb rn, #imm`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch taken, uint64_t address]. */ + * Returns tuple of type [bool branch isTaken, uint64_t address]. */ template std::tuple condBranch_cmpToZero( srcValContainer& sourceValues, @@ -91,7 +91,7 @@ T cs_4ops(srcValContainer& sourceValues, /** Helper function for instructions with the format `tb rn, #imm, * label`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch taken, uint64_t address]. */ + * Returns tuple of type [bool branch isTaken, uint64_t address]. */ template std::tuple tbnz_tbz( srcValContainer& sourceValues, diff --git a/src/include/simeng/config/yaml/ryml.hh b/src/include/simeng/config/yaml/ryml.hh index bed8f4620b..c35a4925f9 100644 --- a/src/include/simeng/config/yaml/ryml.hh +++ b/src/include/simeng/config/yaml/ryml.hh @@ -229,7 +229,7 @@ #define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch)) -/** A preprocessor foreach. Spectacular trick taken from: +/** A preprocessor foreach. Spectacular trick isTaken from: * http://stackoverflow.com/a/1872506/5875572 * The first argument is for a macro receiving a single argument, * which will be called with every subsequent argument. There is @@ -1449,7 +1449,7 @@ using std::index_sequence_for; /** C++11 implementation of integer sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template struct integer_sequence { @@ -1461,7 +1461,7 @@ struct integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence = integer_sequence; @@ -1544,19 +1544,19 @@ struct __make_integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_index_sequence = make_integer_sequence; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence_for = make_index_sequence; #endif @@ -4795,7 +4795,7 @@ namespace detail { /** @internal * @ingroup hash - * @see this was taken a great answer in stackoverflow: + * @see this was isTaken a great answer in stackoverflow: * https://stackoverflow.com/a/34597785/5875572 * @see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/ */ template @@ -12377,7 +12377,7 @@ inline size_t scan_one(csubstr str, const char *type_fmt, T *v) * * So we fake it by using a dynamic format with an explicit * field size set to the length of the given span. - * This trick is taken from: + * This trick is isTaken from: * https://stackoverflow.com/a/18368910/5875572 */ /* this is the actual format we'll use for scanning */ @@ -14624,7 +14624,7 @@ C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, substr buf, c namespace c4 { -//! taken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum +//! isTaken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum template using is_scoped_enum = std::integral_constant::value && !std::is_convertible::value>; @@ -15704,7 +15704,7 @@ template using cspanrs = spanrs; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- /** A non-owning span which always retains the capacity of the original - * range it was taken from (though it may loose its original size). + * range it was isTaken from (though it may loose its original size). * The resizing methods resize(), ltrim(), rtrim() as well * as the subselection methods subspan(), range(), first() and last() can be * used at will without loosing the original capacity; the full capacity span diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 06875a51c5..99c0926426 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -11,8 +11,8 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) globalHistoryLength_( config["Branch-Predictor"]["Global-History-Length"].as()), rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { - // Calculate the saturation counter boundary between weakly taken and - // not-taken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly taken state + // Calculate the saturation counter boundary between weakly isTaken and + // not-isTaken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly isTaken state // value uint8_t weaklyTaken = 1 << (satCntBits_ - 1); uint8_t satCntVal = (config["Branch-Predictor"]["Fallback-Static-Predictor"] @@ -53,9 +53,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Amend prediction based on branch type if (type == BranchType::Unconditional) { - prediction.taken = true; + prediction.isTaken = true; } else if (type == BranchType::Return) { - prediction.taken = true; + prediction.isTaken = true; // Return branches can use the RAS if an entry is available if (ras_.size() > 0) { prediction.target = ras_.back(); @@ -64,7 +64,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, ras_.pop_back(); } } else if (type == BranchType::SubroutineCall) { - prediction.taken = true; + prediction.isTaken = true; // Subroutine call branches must push their associated return address to RAS if (ras_.size() >= rasSize_) { ras_.pop_front(); @@ -73,20 +73,20 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Record that this address is a branch-and-link instruction rasHistory_[address] = 0; } else if (type == BranchType::Conditional) { - if (!prediction.taken) prediction.target = address + 4; + if (!prediction.isTaken) prediction.target = address + 4; } // Store the hashed index for correct hashing in update() - ftq_.emplace_back(prediction.taken, hashedIndex); + ftq_.emplace_back(prediction.isTaken, hashedIndex); // Speculatively update the global history globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; return prediction; } -void GenericPredictor::update(uint64_t address, bool taken, +void GenericPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) { // Get previous prediction and index calculated from the FTQ bool prevPrediction = ftq_.front().first; @@ -96,16 +96,16 @@ void GenericPredictor::update(uint64_t address, bool taken, // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; // Only alter value if it would transition to a valid state - if (!((satCntVal == (1 << satCntBits_) - 1) && taken) && - !(satCntVal == 0 && !taken)) { - satCntVal += taken ? 1 : -1; + if (!((satCntVal == (1 << satCntBits_) - 1) && isTaken) && + !(satCntVal == 0 && !isTaken)) { + satCntVal += isTaken ? 1 : -1; } // Update BTB entry btb_[hashedIndex] = {satCntVal, targetAddress}; // Update global history if prediction was incorrect - if (prevPrediction != taken) { + if (prevPrediction != isTaken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ globalHistory_ ^= (1 << (ftq_.size())); @@ -141,13 +141,13 @@ void GenericPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void GenericPredictor::addToFTQ(uint64_t address, bool taken) { +void GenericPredictor::addToFTQ(uint64_t address, bool isTaken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - ftq_.emplace_back(taken, hashedIndex); + ftq_.emplace_back(isTaken, hashedIndex); // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; + globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 9acd49a4d8..e45cee47b0 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -21,7 +21,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Set up training threshold according to empirically determined formula trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); - globalHistoryMask_ = (globalHistoryLength_ * 2) - 1; + globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; } PerceptronPredictor::~PerceptronPredictor() { @@ -56,9 +56,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Amend prediction based on branch type if (type == BranchType::Unconditional) { - prediction.taken = true; + prediction.isTaken = true; } else if (type == BranchType::Return) { - prediction.taken = true; + prediction.isTaken = true; // Return branches can use the RAS if an entry is available if (ras_.size() > 0) { prediction.target = ras_.back(); @@ -67,7 +67,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, ras_.pop_back(); } } else if (type == BranchType::SubroutineCall) { - prediction.taken = true; + prediction.isTaken = true; // Subroutine call branches must push their associated return address to RAS if (ras_.size() >= rasSize_) { ras_.pop_front(); @@ -76,22 +76,22 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Record that this address is a branch-and-link instruction rasHistory_[address] = 0; } else if (type == BranchType::Conditional) { - if (!prediction.taken) prediction.target = address + 4; + if (!prediction.isTaken) prediction.target = address + 4; } // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - ftq_.emplace_back(prediction.taken, globalHistory_); + ftq_.emplace_back(prediction.isTaken, globalHistory_); // speculatively update global history globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; return prediction; } -void PerceptronPredictor::update(uint64_t address, bool taken, +void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) { // Get previous branch state and prediction from FTQ bool prevPrediction = ftq_.front().first; @@ -110,6 +110,8 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update the perceptron if the prediction was wrong, or the dot product's // magnitude was not greater than the training threshold + if ((directionPrediction != isTaken) || (abs(Pout) < trainingThreshold_)) { + int8_t t = (isTaken) ? 1 : -1; if ((directionPrediction != taken) || (static_cast(std::abs(Pout)) < trainingThreshold_)) { int8_t t = (taken) ? 1 : -1; @@ -135,7 +137,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (prevPrediction != taken) globalHistory_ ^= (1 << (ftq_.size())); + if (prevPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -166,10 +168,10 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { +void PerceptronPredictor::addToFTQ(uint64_t address, bool isTaken) { // Add instruction to the FTQ in event of reused prediction - ftq_.emplace_back(taken, globalHistory_); - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; + ftq_.emplace_back(isTaken, globalHistory_); + globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; } int64_t PerceptronPredictor::getDotProduct( diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 13c75117df..1bf93c451f 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -106,9 +106,9 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as taken, it will require a + // Instruction isn't a branch; if predicted as isTaken, it will require a // flush - return {prediction_.taken, instructionAddress_ + 4}; + return {prediction_.isTaken, instructionAddress_ + 4}; } // Not enough information to determine this was a misprediction diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index 29c4793c44..5eb1091c6b 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -101,9 +101,9 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as taken, it will require a + // Instruction isn't a branch; if predicted as isTaken, it will require a // flush - return {prediction_.taken, instructionAddress_ + 4}; + return {prediction_.isTaken, instructionAddress_ + 4}; } // Not enough information to determine this was a misprediction diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 419accce76..fd7ed45cf9 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -56,7 +56,7 @@ void FetchUnit::tick() { // Let the branch predictor know the prediction is being reused so that // the FTQ can be kept up to date branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchPrediction().taken); + macroOp[0]->getBranchPrediction().isTaken); branchesExecuted_++; } @@ -165,7 +165,7 @@ void FetchUnit::tick() { if (pc_ == loopBoundaryAddress_) { if (macroOp[0]->isBranch() && - !macroOp[0]->getBranchPrediction().taken) { + !macroOp[0]->getBranchPrediction().isTaken) { // loopBoundaryAddress_ has been fetched whilst filling the loop // buffer BUT this is a branch, predicted to branch out of the loop // being buffered. Stop filling the loop buffer and don't supply to @@ -193,11 +193,11 @@ void FetchUnit::tick() { bufferOffset += bytesRead; bufferedBytes_ -= bytesRead; - if (!prediction.taken) { - // Predicted as not taken; increment PC to next instruction + if (!prediction.isTaken) { + // Predicted as not isTaken; increment PC to next instruction pc_ += bytesRead; } else { - // Predicted as taken; set PC to predicted target address + // Predicted as isTaken; set PC to predicted target address pc_ = prediction.target; } @@ -206,7 +206,7 @@ void FetchUnit::tick() { break; } - if (prediction.taken) { + if (prediction.isTaken) { if (slot + 1 < output_.getWidth()) { branchStalls_++; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 2fe34f48a3..6f1db4f449 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -24,7 +24,7 @@ TEST_F(GenericPredictorTest, Miss) { "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); simeng::config::SimInfo::addToConfig( "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 11, " @@ -32,9 +32,9 @@ TEST_F(GenericPredictorTest, Miss) { "Fallback-Static-Predictor: Always-Not-Taken}}"); predictor = simeng::GenericPredictor(); prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); prediction = predictor.predict(8, BranchType::Unconditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); } // Tests that a GenericPredictor will predict branch-and-link return pairs @@ -46,35 +46,35 @@ TEST_F(GenericPredictorTest, RAS) { "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); prediction = predictor.predict(56, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 64); prediction = predictor.predict(72, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 80); prediction = predictor.predict(84, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 76); prediction = predictor.predict(68, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 60); prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -98,7 +98,7 @@ TEST_F(GenericPredictorTest, Hit) { predictor.update(0, true, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); } @@ -133,7 +133,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB predictor.update(0x7C, true, 0xAB, BranchType::Conditional); @@ -161,7 +161,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB predictor.update(0x7C, true, 0xBA, BranchType::Conditional); @@ -189,7 +189,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB predictor.update(0x7C, true, 0xAB, BranchType::Conditional); @@ -217,7 +217,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } @@ -231,21 +231,21 @@ TEST_F(GenericPredictorTest, flush) { auto predictor = simeng::GenericPredictor(); // Add some entries to the RAS auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); // Start getting entries from RAS prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); // Flush address @@ -253,10 +253,10 @@ TEST_F(GenericPredictorTest, flush) { // Continue getting entries from RAS prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(16, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -282,7 +282,7 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x4); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); @@ -302,7 +302,7 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 70485355dd..e8ce9d5747 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -23,9 +23,9 @@ TEST_F(PerceptronPredictorTest, Miss) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); prediction = predictor.predict(8, BranchType::Unconditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); } // Tests that the PerceptronPredictor will predict branch-and-link return pairs @@ -36,35 +36,35 @@ TEST_F(PerceptronPredictorTest, RAS) { "Global-History-Length: 10, RAS-entries: 10}}"); auto predictor = simeng::PerceptronPredictor(); auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); prediction = predictor.predict(56, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 64); prediction = predictor.predict(72, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 80); prediction = predictor.predict(84, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 76); prediction = predictor.predict(68, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 60); prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -87,7 +87,7 @@ TEST_F(PerceptronPredictorTest, Hit) { predictor.update(0, true, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); } @@ -121,7 +121,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB predictor.update(0x7C, false, 0x80, BranchType::Conditional); @@ -149,7 +149,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB predictor.update(0x7C, true, 0xBA, BranchType::Conditional); @@ -177,7 +177,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB predictor.update(0x7C, true, 0x80, BranchType::Conditional); @@ -205,7 +205,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } @@ -218,21 +218,21 @@ TEST_F(PerceptronPredictorTest, flush) { auto predictor = simeng::PerceptronPredictor(); // Add some entries to the RAS auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); // Start getting entries from RAS prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); // Flush address @@ -240,10 +240,10 @@ TEST_F(PerceptronPredictorTest, flush) { // Continue getting entries from RAS prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(16, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -268,8 +268,10 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); - EXPECT_EQ(prediction.target, 0x4); + // Defaults to not-taken + EXPECT_FALSE(prediction.isTaken); + // Should predict target of address + 4 + EXPECT_EQ(prediction.target, 0x103); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); @@ -288,7 +290,7 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 92b8e9393a..00279300b8 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -493,7 +493,7 @@ TEST_F(AArch64InstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch taken) is handled correctly +// Test that a correct prediction (branch isTaken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -510,7 +510,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is taken is handled correctly + // Test a correct prediction where branch is isTaken is handled correctly pred = {true, 80 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -522,7 +522,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not taken) is handled correctly +// Test that a correct prediction (branch not isTaken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_notTaken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -539,7 +539,7 @@ TEST_F(AArch64InstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't taken is handled correctly + // Test a correct prediction where a branch isn't isTaken is handled correctly pred = {false, 80 + 4}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -580,7 +580,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 100 + 0x28); } -// Test that an incorrect prediction (wrong taken) is handled correctly +// Test that an incorrect prediction (wrong isTaken) is handled correctly TEST_F(AArch64InstructionTest, incorrectPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -597,7 +597,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - taken is wrong + // Test an incorrect prediction is handled correctly - isTaken is wrong pred = {true, 100 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 8ecdc7d88b..a9b8c07084 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -232,7 +232,7 @@ TEST_P(PipelineFetchUnitTest, halted) { EXPECT_TRUE(fetchUnit.hasHalted()); } -// Tests that fetching a branch instruction (predicted taken) mid block causes a +// Tests that fetching a branch instruction (predicted isTaken) mid block causes a // branch stall + discards the remaining fetched instructions TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { const uint8_t pc = 16; @@ -266,7 +266,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); fetchUnit.tick(); - // For second tick, process a taken branch meaning rest of block is discarded + // For second tick, process a isTaken branch meaning rest of block is discarded // & a new memory block is requested EXPECT_CALL(memory, getCompletedReads()).Times(0); EXPECT_CALL(memory, clearCompletedReads()).Times(1); @@ -388,7 +388,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { } // Tests the functionality of idling the supply to the Loop Buffer one of not -// taken branch at the loopBoundaryAddress_ +// isTaken branch at the loopBoundaryAddress_ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set instructions to be fetched from memory memory::MemoryReadResult memReadResultA = { @@ -432,7 +432,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); - // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the + // Attempt to fill Loop Buffer but prevent it on a not isTaken outcome at the // loopBoundaryAddress_ branch // Tick 4 times to process all 16 bytes of fetched data for (int i = 0; i < 4; i++) { diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index 6103cd4f5c..c40b503a6c 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -467,7 +467,7 @@ TEST_F(RiscVInstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch taken) is handled correctly +// Test that a correct prediction (branch isTaken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -484,7 +484,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is taken is handled correctly + // Test a correct prediction where branch is isTaken is handled correctly pred = {true, 400 - 86}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -497,7 +497,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not taken) is handled correctly +// Test that a correct prediction (branch not isTaken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_notTaken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -514,7 +514,7 @@ TEST_F(RiscVInstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't taken is handled correctly + // Test a correct prediction where a branch isn't isTaken is handled correctly // imm operand 0x28 has 4 added implicitly by dissassembler pred = {false, 400 + 4}; insn.setBranchPrediction(pred); @@ -559,7 +559,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 400 - 86); } -// Test that an incorrect prediction (wrong taken) is handled correctly +// Test that an incorrect prediction (wrong isTaken) is handled correctly TEST_F(RiscVInstructionTest, incorrectPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -576,7 +576,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - taken is wrong + // Test an incorrect prediction is handled correctly - isTaken is wrong // imm operand 0x28 has 4 added implicitly by dissassembler pred = {true, 400 - 86}; insn.setBranchPrediction(pred); From f5afa999a3639669daaba49d09aa748e88af16bd Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:06:56 +0100 Subject: [PATCH 031/191] Adding comments explaining more basically the nature of the global history --- src/include/simeng/GenericPredictor.hh | 5 +++-- src/include/simeng/PerceptronPredictor.hh | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 7690c11b33..d004daf412 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -59,8 +59,9 @@ class GenericPredictor : public BranchPredictor { /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; - /** A n-bit history of previous branch directions where n is equal to - * globalHistoryLength_. */ + /** An n-bit history of previous branch directions where n is equal to + * globalHistoryLength_. Each bit represents a branch taken (1) or not + * taken (0), with the most recent branch being the least-significant-bit */ uint64_t globalHistory_ = 0; /** The number of previous branch directions recorded globally. */ diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 9236e9e01e..167931372f 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -68,7 +68,8 @@ class PerceptronPredictor : public BranchPredictor { std::deque> ftq_; /** An n-bit history of previous branch directions where n is equal to - * globalHistoryLength_. */ + * globalHistoryLength_. Each bit represents a branch taken (1) or not + * taken (0), with the most recent branch being the least-significant-bit */ uint64_t globalHistory_ = 0; /** The number of previous branch directions recorded globally. */ From b81f8375c1f87fde20539c11277bd4dc23f03ca0 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:18:38 +0100 Subject: [PATCH 032/191] replacing top/bottom with front/back in the docs when referring to a queue --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index b6a58d091a..5dcd3eb69b 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,7 +17,7 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottom of the queue on ``update`` and from the top of the queue on ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the front of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the back of the queue on ``update`` and from the front of the queue on ``flush``. Generic Predictor ----------------- From 84e4edeba8266e39ee1a4700aa362d39316a1e98 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:20:45 +0100 Subject: [PATCH 033/191] Replacing left-most with most-significant --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 5dcd3eb69b..58b3eeaaf9 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. From c5ec7f1ed16e0ac2803c0fc28f30bf9f9667006d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 09:27:48 +0100 Subject: [PATCH 034/191] Replacing left-most with most-significant --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 58b3eeaaf9..e170afe262 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. From ce3f11826ea52170b3efec0c13125bac10d6279f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 13:51:38 +0100 Subject: [PATCH 035/191] Moving BP files to new directory --- src/include/simeng/AlwaysNotTakenPredictor.hh | 2 +- src/include/simeng/CoreInstance.hh | 4 ++-- src/include/simeng/Instruction.hh | 2 +- src/include/simeng/arch/Architecture.hh | 2 +- src/include/simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 2 +- src/include/simeng/{ => branchPredictors}/BranchPredictor.hh | 0 src/include/simeng/{ => branchPredictors}/GenericPredictor.hh | 2 +- .../simeng/{ => branchPredictors}/PerceptronPredictor.hh | 2 +- src/include/simeng/pipeline/ExecuteUnit.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 2 +- src/lib/CMakeLists.txt | 4 ++-- src/lib/{ => branchPredictors}/GenericPredictor.cc | 2 +- src/lib/{ => branchPredictors}/PerceptronPredictor.cc | 2 +- test/regression/RegressionTest.cc | 4 ++-- test/unit/GenericPredictorTest.cc | 2 +- test/unit/MockBranchPredictor.hh | 2 +- test/unit/PerceptronPredictorTest.cc | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) rename src/include/simeng/{ => branchPredictors}/BranchPredictor.hh (100%) rename src/include/simeng/{ => branchPredictors}/GenericPredictor.hh (98%) rename src/include/simeng/{ => branchPredictors}/PerceptronPredictor.hh (98%) rename src/lib/{ => branchPredictors}/GenericPredictor.cc (99%) rename src/lib/{ => branchPredictors}/PerceptronPredictor.cc (99%) diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/AlwaysNotTakenPredictor.hh index fc91e6d9ca..fa05ca8ca9 100644 --- a/src/include/simeng/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/AlwaysNotTakenPredictor.hh @@ -1,6 +1,6 @@ #pragma once -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index 2dc064fa50..a2aa259b57 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -5,12 +5,12 @@ #include "simeng/AlwaysNotTakenPredictor.hh" #include "simeng/Core.hh" #include "simeng/Elf.hh" -#include "simeng/GenericPredictor.hh" -#include "simeng/PerceptronPredictor.hh" #include "simeng/SpecialFileDirGen.hh" #include "simeng/arch/Architecture.hh" #include "simeng/arch/aarch64/Architecture.hh" #include "simeng/arch/riscv/Architecture.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/FixedLatencyMemoryInterface.hh" diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 8ce445402b..94610a209f 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -3,7 +3,7 @@ #include #include "capstone/capstone.h" -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" #include "simeng/memory/MemoryInterface.hh" diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 70782c079c..3b5a1b4fe2 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -3,7 +3,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Core.hh" #include "simeng/Instruction.hh" #include "simeng/arch/ProcessStateChange.hh" diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 315a555a00..c223ed33ce 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -3,7 +3,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/aarch64/InstructionGroups.hh" #include "simeng/arch/aarch64/operandContainer.hh" diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index 888900ba18..dfb6639fcc 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -5,7 +5,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/riscv/InstructionGroups.hh" diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/branchPredictors/BranchPredictor.hh similarity index 100% rename from src/include/simeng/BranchPredictor.hh rename to src/include/simeng/branchPredictors/BranchPredictor.hh diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/branchPredictors/GenericPredictor.hh similarity index 98% rename from src/include/simeng/GenericPredictor.hh rename to src/include/simeng/branchPredictors/GenericPredictor.hh index d004daf412..a288583746 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/branchPredictors/GenericPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/branchPredictors/PerceptronPredictor.hh similarity index 98% rename from src/include/simeng/PerceptronPredictor.hh rename to src/include/simeng/branchPredictors/PerceptronPredictor.hh index 167931372f..c846d045cf 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/branchPredictors/PerceptronPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index c803476873..66433e05d2 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -3,7 +3,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/pipeline/PipelineBuffer.hh" diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index b65d21c61a..2799d54fa9 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { namespace pipeline { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ffabd8bbca..2930f2b1b8 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,6 +14,8 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc + branchPredictors/GenericPredictor.cc + branchPredictors/PerceptronPredictor.cc config/ModelConfig.cc kernel/Linux.cc kernel/LinuxProcess.cc @@ -40,8 +42,6 @@ set(SIMENG_SOURCES CMakeLists.txt CoreInstance.cc Elf.cc - GenericPredictor.cc - PerceptronPredictor.cc RegisterFileSet.cc RegisterValue.cc SpecialFileDirGen.cc diff --git a/src/lib/GenericPredictor.cc b/src/lib/branchPredictors/GenericPredictor.cc similarity index 99% rename from src/lib/GenericPredictor.cc rename to src/lib/branchPredictors/GenericPredictor.cc index 99c0926426..9092f73d52 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/branchPredictors/GenericPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/GenericPredictor.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" #include diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/branchPredictors/PerceptronPredictor.cc similarity index 99% rename from src/lib/PerceptronPredictor.cc rename to src/lib/branchPredictors/PerceptronPredictor.cc index e45cee47b0..8336d62772 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/branchPredictors/PerceptronPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/PerceptronPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" namespace simeng { diff --git a/test/regression/RegressionTest.cc b/test/regression/RegressionTest.cc index d4bf8e3a42..d1502344b1 100644 --- a/test/regression/RegressionTest.cc +++ b/test/regression/RegressionTest.cc @@ -2,8 +2,8 @@ #include -#include "simeng/GenericPredictor.hh" -#include "simeng/PerceptronPredictor.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/kernel/LinuxProcess.hh" diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 6f1db4f449..b24fbee3ff 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/GenericPredictor.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" namespace simeng { diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index a6db5caceb..f09444165d 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -1,7 +1,7 @@ #pragma once #include "gmock/gmock.h" -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index e8ce9d5747..40a36882b7 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/PerceptronPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" namespace simeng { From 4b1b50b26dc58e05bec3cfe37e0def253eb722d8 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 13:54:38 +0100 Subject: [PATCH 036/191] Moving AlwaysNotTakenPredictor files to BP directory --- src/include/simeng/CoreInstance.hh | 2 +- .../simeng/{ => branchPredictors}/AlwaysNotTakenPredictor.hh | 0 src/lib/CMakeLists.txt | 2 +- src/lib/{ => branchPredictors}/AlwaysNotTakenPredictor.cc | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/include/simeng/{ => branchPredictors}/AlwaysNotTakenPredictor.hh (100%) rename src/lib/{ => branchPredictors}/AlwaysNotTakenPredictor.cc (86%) diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index a2aa259b57..2e3f5c6345 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -2,7 +2,7 @@ #include -#include "simeng/AlwaysNotTakenPredictor.hh" +#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" #include "simeng/Core.hh" #include "simeng/Elf.hh" #include "simeng/SpecialFileDirGen.hh" diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh similarity index 100% rename from src/include/simeng/AlwaysNotTakenPredictor.hh rename to src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 2930f2b1b8..08cf1031bf 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -37,7 +37,7 @@ set(SIMENG_SOURCES pipeline/RenameUnit.cc pipeline/ReorderBuffer.cc pipeline/WritebackUnit.cc - AlwaysNotTakenPredictor.cc + branchPredictors/AlwaysNotTakenPredictor.cc ArchitecturalRegisterFileSet.cc CMakeLists.txt CoreInstance.cc diff --git a/src/lib/AlwaysNotTakenPredictor.cc b/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc similarity index 86% rename from src/lib/AlwaysNotTakenPredictor.cc rename to src/lib/branchPredictors/AlwaysNotTakenPredictor.cc index b7f33e6c22..d3f910283b 100644 --- a/src/lib/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/AlwaysNotTakenPredictor.hh" +#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" namespace simeng { From ad0d58a6a386e0a234ab9f20c5e44b09f6ed7811 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 17:03:28 +0100 Subject: [PATCH 037/191] clangformat and undoing some unintended taken -> isTaken --- .../developer/arch/supported/aarch64.rst | 4 ++-- .../developer/components/branchPred.rst | 8 ++++---- .../developer/components/coreinstance.rst | 2 +- .../components/pipeline/components.rst | 2 +- .../developer/components/pipeline/units.rst | 10 +++++----- src/include/simeng/CoreInstance.hh | 2 +- src/include/simeng/Instruction.hh | 10 +++++----- src/include/simeng/arch/Architecture.hh | 2 +- .../simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 2 +- .../AlwaysNotTakenPredictor.hh | 7 ++++--- .../branchPredictors/BranchPredictor.hh | 2 +- src/include/simeng/config/yaml/ryml.hh | 20 +++++++++---------- src/include/simeng/pipeline/ExecuteUnit.hh | 2 +- src/lib/CMakeLists.txt | 2 +- src/lib/arch/aarch64/Instruction.cc | 2 +- src/lib/arch/riscv/Instruction.cc | 2 +- src/lib/branchPredictors/GenericPredictor.cc | 8 ++++---- src/lib/pipeline/FetchUnit.cc | 4 ++-- test/unit/aarch64/InstructionTest.cc | 12 +++++------ test/unit/pipeline/FetchUnitTest.cc | 8 ++++---- test/unit/riscv/InstructionTest.cc | 12 +++++------ 22 files changed, 63 insertions(+), 62 deletions(-) diff --git a/docs/sphinx/developer/arch/supported/aarch64.rst b/docs/sphinx/developer/arch/supported/aarch64.rst index 6df0028e48..092264e991 100644 --- a/docs/sphinx/developer/arch/supported/aarch64.rst +++ b/docs/sphinx/developer/arch/supported/aarch64.rst @@ -55,12 +55,12 @@ Additional information The ``FP`` primary identifier is a placeholder to denote both the ``SCALAR`` and ``VECTOR`` primary identifiers such that, amongst the other combinations, ``FP_SIMPLE_ARTH`` expands to be ``SCALAR_SIMPLE_ARTH`` and ``VECTOR_SIMPLE_ARTH``. In some cases it was unnecessary and inconvenient to separate ``SCALAR`` and ``VECTOR`` operations within configuration options, therefore, this instruction group option was provided to solve the issue. -When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is isTaken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. +When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is taken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. Instruction Splitting ********************* -Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is isTaken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: +Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is taken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: - Load pair for X/W/S/D/Q registers. diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index e170afe262..63cdc8d899 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -30,13 +30,13 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. Static Prediction - Based on the chosen static prediction method of "always isTaken" or "always not isTaken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of isTaken or not-isTaken respectively. + Based on the chosen static prediction method of "always taken" or "always not taken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of taken or not-taken respectively. Perceptron Predictor -------------------- @@ -48,9 +48,9 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. - The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not isTaken if this is negative, or isTaken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. + The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not taken if this is negative, or taken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. \ No newline at end of file diff --git a/docs/sphinx/developer/components/coreinstance.rst b/docs/sphinx/developer/components/coreinstance.rst index 89b6247db4..8b9e99a449 100644 --- a/docs/sphinx/developer/components/coreinstance.rst +++ b/docs/sphinx/developer/components/coreinstance.rst @@ -3,7 +3,7 @@ Core Instance The ``CoreInstance`` component supplies the functionality for instantiating all simulation objects and linking them together. -The standard process isTaken to create an instance of the modelled core is as follows: +The standard process taken to create an instance of the modelled core is as follows: Process the config file Either the passed configuration file path, or default configuration string, is used to generate the model configuration class. All subsequent parameterised instantiations of simulation objects utilise this configuration class. diff --git a/docs/sphinx/developer/components/pipeline/components.rst b/docs/sphinx/developer/components/pipeline/components.rst index f74d5e892e..ab62a6b919 100644 --- a/docs/sphinx/developer/components/pipeline/components.rst +++ b/docs/sphinx/developer/components/pipeline/components.rst @@ -69,7 +69,7 @@ Once a completion slot is available, the load will be executed, the results broa Stores ****** -As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is isTaken from the ``storeQueue_`` entry. +As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is taken from the ``storeQueue_`` entry. The generation of store instruction write requests are carried out after its commitment. The reasoning for this design decision is as followed. With SimEng supporting speculative execution, processed store instruction may come from an incorrectly speculated branch direction and will inevitably be removed from the pipeline. Therefore, it is important to ensure any write requests are valid, concerning speculative execution, as the performance cost of reversing a completed write request is high. diff --git a/docs/sphinx/developer/components/pipeline/units.rst b/docs/sphinx/developer/components/pipeline/units.rst index 922b24f5a6..52358f4658 100644 --- a/docs/sphinx/developer/components/pipeline/units.rst +++ b/docs/sphinx/developer/components/pipeline/units.rst @@ -23,7 +23,7 @@ Behaviour The fetch unit fetches memory in discrete boundary-aligned blocks, according to the current program counter (PC); this is to prevent the fetched block overlapping an inaccessible or unmapped memory region that may result in the request incorrectly responding with a fault despite the validity of the initial region. -Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a isTaken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. +Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a taken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. This standard process of pre-decoding, predicting, and updating the PC continues until one of the following occurs: @@ -32,7 +32,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues The maximum number of fetched macro-ops is reached The current block is saved and processing resumes in the next cycle. - A branch is predicted as isTaken + A branch is predicted as taken A block of memory from the new address may be requested, and processing will resume once the data is available. The fetched memory block is exhausted @@ -43,7 +43,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues Loop Buffer *********** -Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is isTaken and increases the throughput of the fetch unit. +Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is taken and increases the throughput of the fetch unit. Each entry of the loop buffer is the encoding of the Macro-Op. Therefore, when supplying an instruction from the loop buffer, the pre-decoding step must still be performed. This was required to avoid any issues with multiple instantiations of the same instruction editing each others class members. @@ -59,7 +59,7 @@ FILLING The branch representing the loop has been found and the buffer is being filled until it is seen again. SUPPLYING - The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is isTaken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. + The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is taken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. The detection of a loop and the branch which represents it comes from the ROB. More information can be found :ref:`here `. @@ -81,7 +81,7 @@ Behaviour Each cycle, the decode unit will read macro-ops from the input buffer, and split them into a stream of ``Instruction`` objects or micro-ops. These ``Instruction`` objects are passed into an internal buffer. -Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a isTaken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. +Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a taken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. The cycle ends when all ``Instruction`` objects in the internal buffer have been processed, or a misprediction is identified and all remaining ``Instruction`` objects are flushed. diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index 2e3f5c6345..b66519bf64 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -2,13 +2,13 @@ #include -#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" #include "simeng/Core.hh" #include "simeng/Elf.hh" #include "simeng/SpecialFileDirGen.hh" #include "simeng/arch/Architecture.hh" #include "simeng/arch/aarch64/Architecture.hh" #include "simeng/arch/riscv/Architecture.hh" +#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" #include "simeng/branchPredictors/GenericPredictor.hh" #include "simeng/branchPredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 94610a209f..107497d5ea 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -3,9 +3,9 @@ #include #include "capstone/capstone.h" -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/memory/MemoryInterface.hh" #include "simeng/span.hh" @@ -147,15 +147,15 @@ class Instruction { /** Retrieve branch address. */ uint64_t getBranchAddress() const { return branchAddress_; } - /** Was the branch isTaken? */ + /** Was the branch taken? */ bool wasBranchTaken() const { return branchTaken_; } /** Check for misprediction. */ bool wasBranchMispredicted() const { assert(executed_ && "Branch misprediction check requires instruction to have executed"); - // Flag as mispredicted if isTaken state was wrongly predicted, or isTaken and - // predicted target is wrong + // Flag as mispredicted if taken state was wrongly predicted, or taken + // and predicted target is wrong return (branchTaken_ != prediction_.isTaken || (prediction_.target != branchAddress_)); } @@ -289,7 +289,7 @@ class Instruction { /** A branching address calculated by this instruction during execution. */ uint64_t branchAddress_ = 0; - /** Was the branch isTaken? */ + /** Was the branch taken? */ bool branchTaken_ = false; /** What type of branch this instruction is. */ diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 3b5a1b4fe2..1a28a0bd08 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -3,10 +3,10 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Core.hh" #include "simeng/Instruction.hh" #include "simeng/arch/ProcessStateChange.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/MemoryInterface.hh" diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index c223ed33ce..7bf9341ded 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -3,10 +3,10 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/aarch64/InstructionGroups.hh" #include "simeng/arch/aarch64/operandContainer.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" struct cs_arm64_op; diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index dfb6639fcc..69257153d8 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -5,9 +5,9 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/riscv/InstructionGroups.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { namespace arch { diff --git a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh index fa05ca8ca9..b43c361e54 100644 --- a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh @@ -4,12 +4,13 @@ namespace simeng { -/** An "Always Not Taken" branch predictor; predicts all branches as not isTaken. +/** An "Always Not Taken" branch predictor; predicts all branches as not + * taken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will - * always predict not isTaken. */ + * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset) override; @@ -19,7 +20,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { BranchType type) override; /** Provide flush logic for branch prediction scheme. As there's no flush - * logic for an always isTaken predictor, this does nothing. */ + * logic for an always taken predictor, this does nothing. */ void flush(uint64_t address) override; }; diff --git a/src/include/simeng/branchPredictors/BranchPredictor.hh b/src/include/simeng/branchPredictors/BranchPredictor.hh index c4da8e1ff9..2bcf76eb25 100644 --- a/src/include/simeng/branchPredictors/BranchPredictor.hh +++ b/src/include/simeng/branchPredictors/BranchPredictor.hh @@ -17,7 +17,7 @@ enum class BranchType { /** A branch result prediction for an instruction. */ struct BranchPrediction { - /** Whether the branch will be isTaken. */ + /** Whether the branch will be taken. */ bool isTaken; /** The branch instruction's target address. If `isTaken = false`, the value diff --git a/src/include/simeng/config/yaml/ryml.hh b/src/include/simeng/config/yaml/ryml.hh index c35a4925f9..bed8f4620b 100644 --- a/src/include/simeng/config/yaml/ryml.hh +++ b/src/include/simeng/config/yaml/ryml.hh @@ -229,7 +229,7 @@ #define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch)) -/** A preprocessor foreach. Spectacular trick isTaken from: +/** A preprocessor foreach. Spectacular trick taken from: * http://stackoverflow.com/a/1872506/5875572 * The first argument is for a macro receiving a single argument, * which will be called with every subsequent argument. There is @@ -1449,7 +1449,7 @@ using std::index_sequence_for; /** C++11 implementation of integer sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template struct integer_sequence { @@ -1461,7 +1461,7 @@ struct integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence = integer_sequence; @@ -1544,19 +1544,19 @@ struct __make_integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_index_sequence = make_integer_sequence; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence_for = make_index_sequence; #endif @@ -4795,7 +4795,7 @@ namespace detail { /** @internal * @ingroup hash - * @see this was isTaken a great answer in stackoverflow: + * @see this was taken a great answer in stackoverflow: * https://stackoverflow.com/a/34597785/5875572 * @see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/ */ template @@ -12377,7 +12377,7 @@ inline size_t scan_one(csubstr str, const char *type_fmt, T *v) * * So we fake it by using a dynamic format with an explicit * field size set to the length of the given span. - * This trick is isTaken from: + * This trick is taken from: * https://stackoverflow.com/a/18368910/5875572 */ /* this is the actual format we'll use for scanning */ @@ -14624,7 +14624,7 @@ C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, substr buf, c namespace c4 { -//! isTaken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum +//! taken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum template using is_scoped_enum = std::integral_constant::value && !std::is_convertible::value>; @@ -15704,7 +15704,7 @@ template using cspanrs = spanrs; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- /** A non-owning span which always retains the capacity of the original - * range it was isTaken from (though it may loose its original size). + * range it was taken from (though it may loose its original size). * The resizing methods resize(), ltrim(), rtrim() as well * as the subselection methods subspan(), range(), first() and last() can be * used at will without loosing the original capacity; the full capacity span diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index 66433e05d2..e6420e998f 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -3,8 +3,8 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/pipeline/PipelineBuffer.hh" namespace simeng { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 08cf1031bf..7a002bf8a0 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,6 +14,7 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc + branchPredictors/AlwaysNotTakenPredictor.cc branchPredictors/GenericPredictor.cc branchPredictors/PerceptronPredictor.cc config/ModelConfig.cc @@ -37,7 +38,6 @@ set(SIMENG_SOURCES pipeline/RenameUnit.cc pipeline/ReorderBuffer.cc pipeline/WritebackUnit.cc - branchPredictors/AlwaysNotTakenPredictor.cc ArchitecturalRegisterFileSet.cc CMakeLists.txt CoreInstance.cc diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 1bf93c451f..e3b697433e 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -106,7 +106,7 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as isTaken, it will require a + // Instruction isn't a branch; if predicted as taken, it will require a // flush return {prediction_.isTaken, instructionAddress_ + 4}; } diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index 5eb1091c6b..c71b581a60 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -101,7 +101,7 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as isTaken, it will require a + // Instruction isn't a branch; if predicted as taken, it will require a // flush return {prediction_.isTaken, instructionAddress_ + 4}; } diff --git a/src/lib/branchPredictors/GenericPredictor.cc b/src/lib/branchPredictors/GenericPredictor.cc index 9092f73d52..dda9970c03 100644 --- a/src/lib/branchPredictors/GenericPredictor.cc +++ b/src/lib/branchPredictors/GenericPredictor.cc @@ -11,8 +11,8 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) globalHistoryLength_( config["Branch-Predictor"]["Global-History-Length"].as()), rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { - // Calculate the saturation counter boundary between weakly isTaken and - // not-isTaken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly isTaken state + // Calculate the saturation counter boundary between weakly taken and + // not-taken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly taken state // value uint8_t weaklyTaken = 1 << (satCntBits_ - 1); uint8_t satCntVal = (config["Branch-Predictor"]["Fallback-Static-Predictor"] @@ -143,8 +143,8 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool isTaken) { // Make the hashed index and add it to the FTQ - uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - - 1); + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); ftq_.emplace_back(isTaken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index fd7ed45cf9..104bb3f07a 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -194,10 +194,10 @@ void FetchUnit::tick() { bufferedBytes_ -= bytesRead; if (!prediction.isTaken) { - // Predicted as not isTaken; increment PC to next instruction + // Predicted as not taken; increment PC to next instruction pc_ += bytesRead; } else { - // Predicted as isTaken; set PC to predicted target address + // Predicted as taken; set PC to predicted target address pc_ = prediction.target; } diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 00279300b8..92b8e9393a 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -493,7 +493,7 @@ TEST_F(AArch64InstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch isTaken) is handled correctly +// Test that a correct prediction (branch taken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -510,7 +510,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is isTaken is handled correctly + // Test a correct prediction where branch is taken is handled correctly pred = {true, 80 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -522,7 +522,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not isTaken) is handled correctly +// Test that a correct prediction (branch not taken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_notTaken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -539,7 +539,7 @@ TEST_F(AArch64InstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't isTaken is handled correctly + // Test a correct prediction where a branch isn't taken is handled correctly pred = {false, 80 + 4}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -580,7 +580,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 100 + 0x28); } -// Test that an incorrect prediction (wrong isTaken) is handled correctly +// Test that an incorrect prediction (wrong taken) is handled correctly TEST_F(AArch64InstructionTest, incorrectPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -597,7 +597,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - isTaken is wrong + // Test an incorrect prediction is handled correctly - taken is wrong pred = {true, 100 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index a9b8c07084..8ecdc7d88b 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -232,7 +232,7 @@ TEST_P(PipelineFetchUnitTest, halted) { EXPECT_TRUE(fetchUnit.hasHalted()); } -// Tests that fetching a branch instruction (predicted isTaken) mid block causes a +// Tests that fetching a branch instruction (predicted taken) mid block causes a // branch stall + discards the remaining fetched instructions TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { const uint8_t pc = 16; @@ -266,7 +266,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); fetchUnit.tick(); - // For second tick, process a isTaken branch meaning rest of block is discarded + // For second tick, process a taken branch meaning rest of block is discarded // & a new memory block is requested EXPECT_CALL(memory, getCompletedReads()).Times(0); EXPECT_CALL(memory, clearCompletedReads()).Times(1); @@ -388,7 +388,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { } // Tests the functionality of idling the supply to the Loop Buffer one of not -// isTaken branch at the loopBoundaryAddress_ +// taken branch at the loopBoundaryAddress_ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set instructions to be fetched from memory memory::MemoryReadResult memReadResultA = { @@ -432,7 +432,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); - // Attempt to fill Loop Buffer but prevent it on a not isTaken outcome at the + // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the // loopBoundaryAddress_ branch // Tick 4 times to process all 16 bytes of fetched data for (int i = 0; i < 4; i++) { diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index c40b503a6c..6103cd4f5c 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -467,7 +467,7 @@ TEST_F(RiscVInstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch isTaken) is handled correctly +// Test that a correct prediction (branch taken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -484,7 +484,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is isTaken is handled correctly + // Test a correct prediction where branch is taken is handled correctly pred = {true, 400 - 86}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -497,7 +497,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not isTaken) is handled correctly +// Test that a correct prediction (branch not taken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_notTaken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -514,7 +514,7 @@ TEST_F(RiscVInstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't isTaken is handled correctly + // Test a correct prediction where a branch isn't taken is handled correctly // imm operand 0x28 has 4 added implicitly by dissassembler pred = {false, 400 + 4}; insn.setBranchPrediction(pred); @@ -559,7 +559,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 400 - 86); } -// Test that an incorrect prediction (wrong isTaken) is handled correctly +// Test that an incorrect prediction (wrong taken) is handled correctly TEST_F(RiscVInstructionTest, incorrectPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -576,7 +576,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - isTaken is wrong + // Test an incorrect prediction is handled correctly - taken is wrong // imm operand 0x28 has 4 added implicitly by dissassembler pred = {true, 400 - 86}; insn.setBranchPrediction(pred); From b2d6ae8976c7c3b7eed6fc5baf46149e1d7dce8f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:08:09 +0100 Subject: [PATCH 038/191] rebase --- src/include/simeng/CoreInstance.hh | 6 +- src/include/simeng/Instruction.hh | 2 +- src/include/simeng/arch/Architecture.hh | 2 +- .../simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 2 +- .../AlwaysNotTakenPredictor.hh | 5 +- .../BranchPredictor.hh | 14 +-- .../GenericPredictor.hh | 31 +++-- .../PerceptronPredictor.hh | 38 ++++--- src/include/simeng/pipeline/ExecuteUnit.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 2 +- src/lib/CMakeLists.txt | 6 +- .../AlwaysNotTakenPredictor.cc | 2 +- .../GenericPredictor.cc | 33 +++--- .../PerceptronPredictor.cc | 58 ++++++---- src/lib/pipeline/FetchUnit.cc | 5 +- test/regression/RegressionTest.cc | 4 +- test/unit/GenericPredictorTest.cc | 106 +++++++++--------- test/unit/MockBranchPredictor.hh | 8 +- test/unit/PerceptronPredictorTest.cc | 106 +++++++++--------- test/unit/pipeline/FetchUnitTest.cc | 11 +- 21 files changed, 249 insertions(+), 196 deletions(-) rename src/include/simeng/{branchPredictors => branchpredictors}/AlwaysNotTakenPredictor.hh (80%) rename src/include/simeng/{branchPredictors => branchpredictors}/BranchPredictor.hh (81%) rename src/include/simeng/{branchPredictors => branchpredictors}/GenericPredictor.hh (70%) rename src/include/simeng/{branchPredictors => branchpredictors}/PerceptronPredictor.hh (69%) rename src/lib/{branchPredictors => branchpredictors}/AlwaysNotTakenPredictor.cc (86%) rename src/lib/{branchPredictors => branchpredictors}/GenericPredictor.cc (85%) rename src/lib/{branchPredictors => branchpredictors}/PerceptronPredictor.cc (76%) diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index b66519bf64..64e2f9e1f5 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -8,9 +8,9 @@ #include "simeng/arch/Architecture.hh" #include "simeng/arch/aarch64/Architecture.hh" #include "simeng/arch/riscv/Architecture.hh" -#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" -#include "simeng/branchPredictors/GenericPredictor.hh" -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/AlwaysNotTakenPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/FixedLatencyMemoryInterface.hh" diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 107497d5ea..28824aa05f 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -5,7 +5,7 @@ #include "capstone/capstone.h" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/memory/MemoryInterface.hh" #include "simeng/span.hh" diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 1a28a0bd08..aa293d6f5f 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -6,7 +6,7 @@ #include "simeng/Core.hh" #include "simeng/Instruction.hh" #include "simeng/arch/ProcessStateChange.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/MemoryInterface.hh" diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 7bf9341ded..76e74d7eb7 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -6,7 +6,7 @@ #include "simeng/Instruction.hh" #include "simeng/arch/aarch64/InstructionGroups.hh" #include "simeng/arch/aarch64/operandContainer.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" struct cs_arm64_op; diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index 69257153d8..9e707449c6 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -7,7 +7,7 @@ #include "simeng/Instruction.hh" #include "simeng/arch/riscv/InstructionGroups.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { namespace arch { diff --git a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh similarity index 80% rename from src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh rename to src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index b43c361e54..aad7aa67a3 100644 --- a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -1,6 +1,6 @@ #pragma once -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { @@ -12,7 +12,8 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) override; + int64_t knownOffset, + bool getPrediction = true) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ diff --git a/src/include/simeng/branchPredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh similarity index 81% rename from src/include/simeng/branchPredictors/BranchPredictor.hh rename to src/include/simeng/branchpredictors/BranchPredictor.hh index 2bcf76eb25..8f7b568934 100644 --- a/src/include/simeng/branchPredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -47,9 +47,13 @@ class BranchPredictor { virtual ~BranchPredictor(){}; /** Generate a branch prediction for the specified instruction address with a - * branch type and possible known branch offset. */ - virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) = 0; + * branch type and possible known branch offset. There is and optional + * boolean argument for if no prediction is needed from the branch + * predictor (e.g., in the event that the fetch unit has identified this + * branch as being a part of a queue and so reusing a previous prediction).*/ + virtual BranchPrediction predict( + uint64_t address, BranchType type, int64_t knownOffset, + bool getPrediction = true) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program @@ -63,10 +67,6 @@ class BranchPredictor { * once, the exact order that the individual instructions within this block * are flushed does not matter so long as they are all flushed) */ virtual void flush(uint64_t address) = 0; - - /** Adds instruction to the Fetch Target Queue without making a new prediction - */ - virtual void addToFTQ(uint64_t address, bool isTaken) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchPredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh similarity index 70% rename from src/include/simeng/branchPredictors/GenericPredictor.hh rename to src/include/simeng/branchpredictors/GenericPredictor.hh index a288583746..f30d213dbb 100644 --- a/src/include/simeng/branchPredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { @@ -28,22 +28,28 @@ class GenericPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ + * known. Returns a branch direction and branch target address. Optional + * arguments of getPrediction and pastDirection for use in the event that a + * new prediction is not required from the BP for a branch (e.g., if the + * fetch unit has identified the branch as being a part of a loop and so is + * reusing a previous prediction). If no prediction is required, then the + * direction prediction that is being used in lieu of a new prediction must + * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) override; + int64_t knownOffset = 0, + bool getPrediction = true) override; - /** Updates appropriate predictor model objects based on the address and - * outcome of the branch instruction. */ + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on branches in + * program order. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Provides RAS rewinding behaviour. */ + /** Flushes the most recently predicted branch from the BP. Address is + * required to ensure that only the correct branch is removed from the RAS. + * */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction - */ - void addToFTQ(uint64_t address, bool isTaken) override; - private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ uint8_t btbBits_; @@ -56,6 +62,11 @@ class GenericPredictor : public BranchPredictor { * history state of branches that are currently unresolved */ std::deque> ftq_; + /** Keep the last ftq entry as a separate variable to be reused for loops + * in the event that the ftq_ is empty by the time the next predict() is + * called */ + std::pair lastFtqEntry_; + /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/branchPredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh similarity index 69% rename from src/include/simeng/branchPredictors/PerceptronPredictor.hh rename to src/include/simeng/branchpredictors/PerceptronPredictor.hh index c846d045cf..2d31690fa5 100644 --- a/src/include/simeng/branchPredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { @@ -31,22 +31,28 @@ class PerceptronPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ + * known. Returns a branch direction and branch target address. Optional + * arguments of getPrediction and pastDirection for use in the event that a + * new prediction is not required from the BP for a branch (e.g., if the + * fetch unit has identified the branch as being a part of a loop and so is + * reusing a previous prediction). If no prediction is required, then the + * direction prediction that is being used in lieu of a new prediction must + * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) override; + int64_t knownOffset = 0, + bool getPrediction = true) override; - /** Updates appropriate predictor model objects based on the address and - * outcome of the branch instruction. */ + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on branches in + * program order. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Provides RAS rewinding behaviour. */ + /** Flushes the most recently predicted branch from the BP. Address is + * required to ensure that only the correct branch is removed from the RAS. + * */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction - */ - void addToFTQ(uint64_t address, bool isTaken) override; - private: /** Returns the dot product of a perceptron and a history vector. Used to * determine a direction prediction */ @@ -63,9 +69,15 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** Fetch Target Queue containing the direction prediction and previous global - * history state of branches that are currently unresolved */ - std::deque> ftq_; + /** Fetch Target Queue containing the dot product of the perceptron and the + * global history; and the global history, both at the time of prediction, + * for each of the branches that are currently unresolved. */ + std::deque> ftq_; + + /** Keep the last ftq entry as a separate variable to be reused for loops + * in the event that the ftq_ is empty by the time the next predict() is + * called */ + std::pair lastFtqEntry_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. Each bit represents a branch taken (1) or not diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index e6420e998f..450ad4b384 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -4,7 +4,7 @@ #include #include "simeng/Instruction.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/pipeline/PipelineBuffer.hh" namespace simeng { diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index 2799d54fa9..b6459935ed 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { namespace pipeline { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 7a002bf8a0..ac393b19c2 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,9 +14,9 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc - branchPredictors/AlwaysNotTakenPredictor.cc - branchPredictors/GenericPredictor.cc - branchPredictors/PerceptronPredictor.cc + branchpredictors/AlwaysNotTakenPredictor.cc + branchpredictors/GenericPredictor.cc + branchpredictors/PerceptronPredictor.cc config/ModelConfig.cc kernel/Linux.cc kernel/LinuxProcess.cc diff --git a/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc similarity index 86% rename from src/lib/branchPredictors/AlwaysNotTakenPredictor.cc rename to src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index d3f910283b..847e32740e 100644 --- a/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" +#include "simeng/branchpredictors/AlwaysNotTakenPredictor.hh" namespace simeng { diff --git a/src/lib/branchPredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc similarity index 85% rename from src/lib/branchPredictors/GenericPredictor.cc rename to src/lib/branchpredictors/GenericPredictor.cc index dda9970c03..75a0c9a685 100644 --- a/src/lib/branchPredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" #include @@ -27,6 +27,10 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // outcomes are stored to allow rolling back the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + + // Set dummy lastFtqEntry value, needed to ensure that non-prediction + // getting predict() calls in tests work. + lastFtqEntry_ = {true, 0}; } GenericPredictor::~GenericPredictor() { @@ -36,8 +40,9 @@ GenericPredictor::~GenericPredictor() { ftq_.clear(); } -BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset) { +BranchPrediction GenericPredictor::predict( + uint64_t address, BranchType type, int64_t knownOffset, + bool getPrediction) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -45,6 +50,17 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + // If a branch prediction is not required, then we can avoid a lot of the + // logic, and just determine the direction, and add the branch to the ftq + if (!getPrediction) { + // Add branch to the back of the ftq + ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); + // Speculatively update the global history + globalHistory_ = ((globalHistory_ << 1) | lastFtqEntry_.first) & + globalHistoryMask_; + return {false, 0}; + } + // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = @@ -78,6 +94,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Store the hashed index for correct hashing in update() ftq_.emplace_back(prediction.isTaken, hashedIndex); + lastFtqEntry_ = {prediction.isTaken, hashedIndex}; // Speculatively update the global history globalHistory_ = @@ -140,14 +157,4 @@ void GenericPredictor::flush(uint64_t address) { // Roll back global history globalHistory_ >>= 1; } - -void GenericPredictor::addToFTQ(uint64_t address, bool isTaken) { - // Make the hashed index and add it to the FTQ - uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - ftq_.emplace_back(isTaken, hashedIndex); - // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; -} - } // namespace simeng diff --git a/src/lib/branchPredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc similarity index 76% rename from src/lib/branchPredictors/PerceptronPredictor.cc rename to src/lib/branchpredictors/PerceptronPredictor.cc index 8336d62772..550cb74b87 100644 --- a/src/lib/branchPredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" namespace simeng { @@ -22,6 +22,10 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + + // Set dummy lastFtqEntry value, needed to ensure that non-prediction + // getting predict() calls in tests work. + lastFtqEntry_ = {1, 0}; } PerceptronPredictor::~PerceptronPredictor() { @@ -31,7 +35,24 @@ PerceptronPredictor::~PerceptronPredictor() { } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset) { + int64_t knownOffset, + bool getPrediction) { + // If no prediction required, add branch to ftq and return dummy + // prediction, which will not be used by the fetch unit + if (!getPrediction) { + // Add branch to the ftq using the past dot product in lieu of a new + // prediction. Because the loop buffer only supplies if there have been + // no branch instructions since the branch defining the loop, we know + // that the past dot product is the one most recently added to the ftq_ + ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); + // Update global history + globalHistory_ = + ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & + globalHistoryMask_; + // Return dummy prediction + return {false, 0}; + } + // Get the hashed index for the prediction table. XOR the global history with // the non-zero bits of the address, and then keep only the btbBits_ bits of // the output to keep it in bounds of the prediction table. @@ -48,7 +69,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Determine direction prediction based on its sign bool direction = (Pout >= 0); - // Retrieve target prediction + // If there is a known offset then calculate target accordingly, otherwise + // retrieve the target prediction from the btb. uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; @@ -79,12 +101,14 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, if (!prediction.isTaken) prediction.target = address + 4; } - // Store the global history for correct hashing in update() -- + // Store the Pout and global history for correct update() -- // needs to be global history and not the hashed index as hashing loses - // information at longer global history lengths - ftq_.emplace_back(prediction.isTaken, globalHistory_); + // information and the global history is required for updating perceptrons. + ftq_.emplace_back(Pout, globalHistory_); + lastFtqEntry_ = {Pout, globalHistory_}; - // speculatively update global history + // Speculatively update the global history based on the direction + // prediction being made globalHistory_ = ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; @@ -93,8 +117,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) { - // Get previous branch state and prediction from FTQ - bool prevPrediction = ftq_.front().first; + // Retrieve the previous global history and branch direction prediction from + // the front of the ftq (assumes branches are updated in program order). + int64_t prevPout = ftq_.front().first; uint64_t prevGlobalHistory = ftq_.front().second; ftq_.pop_front(); @@ -102,15 +127,16 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); + std::vector perceptron = btb_[hashedIndex].first; // Work out the most recent prediction - int64_t Pout = getDotProduct(perceptron, prevGlobalHistory); - bool directionPrediction = (Pout >= 0); + bool directionPrediction = (prevPout >= 0); // Update the perceptron if the prediction was wrong, or the dot product's // magnitude was not greater than the training threshold - if ((directionPrediction != isTaken) || (abs(Pout) < trainingThreshold_)) { + if ((directionPrediction != isTaken) || + (abs(prevPout) < trainingThreshold_)) { int8_t t = (isTaken) ? 1 : -1; if ((directionPrediction != taken) || (static_cast(std::abs(Pout)) < trainingThreshold_)) { @@ -137,7 +163,7 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (prevPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); + if (directionPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -168,12 +194,6 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void PerceptronPredictor::addToFTQ(uint64_t address, bool isTaken) { - // Add instruction to the FTQ in event of reused prediction - ftq_.emplace_back(isTaken, globalHistory_); - globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; -} - int64_t PerceptronPredictor::getDotProduct( const std::vector& perceptron, uint64_t history) { int64_t Pout = perceptron[globalHistoryLength_]; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 104bb3f07a..15f8848061 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -55,8 +55,9 @@ void FetchUnit::tick() { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Let the branch predictor know the prediction is being reused so that // the FTQ can be kept up to date - branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchPrediction().isTaken); + branchPredictor_.predict(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset(), false); branchesExecuted_++; } diff --git a/test/regression/RegressionTest.cc b/test/regression/RegressionTest.cc index d1502344b1..237b0518a3 100644 --- a/test/regression/RegressionTest.cc +++ b/test/regression/RegressionTest.cc @@ -2,8 +2,8 @@ #include -#include "simeng/branchPredictors/GenericPredictor.hh" -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/kernel/LinuxProcess.hh" diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index b24fbee3ff..945a767154 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" namespace simeng { @@ -111,25 +111,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -139,25 +139,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -167,25 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -195,25 +195,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -268,17 +268,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -288,17 +288,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index f09444165d..56777c0846 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -1,19 +1,19 @@ #pragma once #include "gmock/gmock.h" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { /** Mock implementation of the `BranchPredictor` interface. */ class MockBranchPredictor : public BranchPredictor { public: - MOCK_METHOD3(predict, BranchPrediction(uint64_t address, BranchType type, - int64_t knownTarget)); + MOCK_METHOD4(predict, + BranchPrediction(uint64_t address, BranchType type, + int64_t knownTarget, bool getPrediction)); MOCK_METHOD4(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type)); MOCK_METHOD1(flush, void(uint64_t address)); - MOCK_METHOD2(addToFTQ, void(uint64_t address, bool taken)); }; } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 40a36882b7..5dca2bcffe 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" namespace simeng { @@ -99,25 +99,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -127,25 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -155,25 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -183,25 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -254,17 +254,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -276,17 +276,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 8ecdc7d88b..ae6311f112 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -94,7 +94,7 @@ TEST_P(PipelineFetchUnitTest, TickStalled) { EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_, _, _)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _, _)).Times(0); fetchUnit.tick(); @@ -279,7 +279,8 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff)).WillOnce(Return(pred)); + EXPECT_CALL(predictor, predict(20, bType, knownOff, true)).WillOnce + (Return(pred)); fetchUnit.tick(); // Ensure on next tick, predecode is not called @@ -325,7 +326,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { // Set the expectation from the predictor to be true so a loop body will // be detected - ON_CALL(predictor, predict(_, _, _)) + ON_CALL(predictor, predict(_, _, _, _)) .WillByDefault(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -417,7 +418,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set the first expectation from the predictor to be true so a loop body will // be detected - EXPECT_CALL(predictor, predict(_, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, _)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -429,7 +430,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the From 5a10cab37deb1dd5ea1b0d1041a87fc28c864c28 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:08:45 +0100 Subject: [PATCH 039/191] rebase --- .../simeng/branchpredictors/AlwaysNotTakenPredictor.hh | 2 +- src/include/simeng/branchpredictors/BranchPredictor.hh | 2 +- src/include/simeng/branchpredictors/GenericPredictor.hh | 2 +- src/include/simeng/branchpredictors/PerceptronPredictor.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 4 ++-- src/lib/branchpredictors/PerceptronPredictor.cc | 4 ++-- src/lib/pipeline/FetchUnit.cc | 2 +- test/unit/pipeline/FetchUnitTest.cc | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index aad7aa67a3..e366488d23 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -13,7 +13,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction = true) override; + bool isLoop = false) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 8f7b568934..197f57263e 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -53,7 +53,7 @@ class BranchPredictor { * branch as being a part of a queue and so reusing a previous prediction).*/ virtual BranchPrediction predict( uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction = true) = 0; + bool isLoop = false) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index f30d213dbb..4b16aad1c8 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -37,7 +37,7 @@ class GenericPredictor : public BranchPredictor { * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, - bool getPrediction = true) override; + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 2d31690fa5..091f5261b0 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -40,7 +40,7 @@ class PerceptronPredictor : public BranchPredictor { * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, - bool getPrediction = true) override; + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 75a0c9a685..f4f5d0548b 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -42,7 +42,7 @@ GenericPredictor::~GenericPredictor() { BranchPrediction GenericPredictor::predict( uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction) { + bool isLoop) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -52,7 +52,7 @@ BranchPrediction GenericPredictor::predict( // If a branch prediction is not required, then we can avoid a lot of the // logic, and just determine the direction, and add the branch to the ftq - if (!getPrediction) { + if (isLoop) { // Add branch to the back of the ftq ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); // Speculatively update the global history diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 550cb74b87..69fc803c40 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -36,10 +36,10 @@ PerceptronPredictor::~PerceptronPredictor() { BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction) { + bool isLoop) { // If no prediction required, add branch to ftq and return dummy // prediction, which will not be used by the fetch unit - if (!getPrediction) { + if (isLoop) { // Add branch to the ftq using the past dot product in lieu of a new // prediction. Because the loop buffer only supplies if there have been // no branch instructions since the branch defining the loop, we know diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 15f8848061..2a48b27cba 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -57,7 +57,7 @@ void FetchUnit::tick() { // the FTQ can be kept up to date branchPredictor_.predict(macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset(), false); + macroOp[0]->getKnownOffset(), true); branchesExecuted_++; } diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index ae6311f112..79092d2e5e 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -279,7 +279,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff, true)).WillOnce + EXPECT_CALL(predictor, predict(20, bType, knownOff, false)).WillOnce (Return(pred)); fetchUnit.tick(); From 1e08ca0cac8a1807df5407876d30a4d098d1709c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 12:16:10 +0100 Subject: [PATCH 040/191] Updating BP tests for consistency with new predict() arguments --- .../AlwaysNotTakenPredictor.hh | 3 +- test/unit/GenericPredictorTest.cc | 104 +++++++++--------- test/unit/PerceptronPredictorTest.cc | 104 +++++++++--------- 3 files changed, 105 insertions(+), 106 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index e366488d23..d057027db5 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -5,8 +5,7 @@ namespace simeng { /** An "Always Not Taken" branch predictor; predicts all branches as not - * taken. - */ + * taken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 945a767154..0c698cd276 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -111,25 +111,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -139,25 +139,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -167,25 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -195,25 +195,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -268,17 +268,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -288,17 +288,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 5dca2bcffe..15d6c88250 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -99,25 +99,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -127,25 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -155,25 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -183,25 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -254,17 +254,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -276,17 +276,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); From 80d3d10b0923d8e0c9b50945fb11d32c4e22ca8d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 12:32:16 +0100 Subject: [PATCH 041/191] Updating docs --- docs/sphinx/developer/components/branchPred.rst | 8 ++++---- src/include/simeng/arch/aarch64/helpers/conditional.hh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 63cdc8d899..767fd1bead 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -3,9 +3,9 @@ Branch prediction SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredictor`` class to enable speculative execution. -Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, ``flush``, and ``addToFTQ``` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, ``flush`` provides optional algorithm specific flushing functionality, and ``addToFTQ`` adds an instruction to the predictor's Fetch Target Queue (FTQ) when a new prediction is not needed. +Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, for a branch instruction. ``update`` updates the branch predictor's prediction mechanism on the actual outcome of a branch. ``flush`` provides algorithm specific flushing functionality. -The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: +The ``predict`` function is passed an instruction address, branch type, a possible known target, and optionally whether the branch is in a loop. The branch type argument currently supports the following types: - ``Conditional`` - ``LoopClosing`` @@ -13,11 +13,11 @@ The ``predict`` function is passed an instruction address, branch type, and a po - ``SubroutineCall`` - ``Unconditional`` -The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. +The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. If the branch is a part of a loop, then only a dummy branch prediction is returned by ``predict``, as the fetch unit will reuse a previous branch prediction and so no new branch prediction is needed. The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the front of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the back of the queue on ``update`` and from the front of the queue on ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the back of the ftq on ``predict``, and a single entry is removed from the front of the queue on ``update`` and from the back of the queue on ``flush``. Generic Predictor ----------------- diff --git a/src/include/simeng/arch/aarch64/helpers/conditional.hh b/src/include/simeng/arch/aarch64/helpers/conditional.hh index 2b3ea1b9c3..e541eb276a 100644 --- a/src/include/simeng/arch/aarch64/helpers/conditional.hh +++ b/src/include/simeng/arch/aarch64/helpers/conditional.hh @@ -56,7 +56,7 @@ uint8_t ccmp_reg(srcValContainer& sourceValues, /** Helper function for instructions with the format `cb rn, #imm`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch isTaken, uint64_t address]. */ + * Returns tuple of type [bool branch taken, uint64_t address]. */ template std::tuple condBranch_cmpToZero( srcValContainer& sourceValues, @@ -91,7 +91,7 @@ T cs_4ops(srcValContainer& sourceValues, /** Helper function for instructions with the format `tb rn, #imm, * label`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch isTaken, uint64_t address]. */ + * Returns tuple of type [bool branch taken, uint64_t address]. */ template std::tuple tbnz_tbz( srcValContainer& sourceValues, From 0b71bf4509896414a83fb020c8557c80c1bb79ee Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 12:52:32 +0100 Subject: [PATCH 042/191] Updating comments --- .../simeng/branchpredictors/BranchPredictor.hh | 12 ++++++------ .../simeng/branchpredictors/GenericPredictor.hh | 13 ++++++------- .../simeng/branchpredictors/PerceptronPredictor.hh | 13 ++++++------- src/include/simeng/pipeline/FetchUnit.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 4 ++++ src/lib/branchpredictors/GenericPredictor.cc | 9 +++++---- src/lib/branchpredictors/PerceptronPredictor.cc | 10 +++++----- src/lib/pipeline/FetchUnit.cc | 6 +++--- 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 197f57263e..da6d486de7 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -47,17 +47,17 @@ class BranchPredictor { virtual ~BranchPredictor(){}; /** Generate a branch prediction for the specified instruction address with a - * branch type and possible known branch offset. There is and optional - * boolean argument for if no prediction is needed from the branch - * predictor (e.g., in the event that the fetch unit has identified this - * branch as being a part of a queue and so reusing a previous prediction).*/ + * branch type and possible known branch offset. There is an optional + * boolean argument for if the branch is a part of a loop, in which case + * the fetch unit does not require a new prediction and so only a dummy + * prediction is returned. */ virtual BranchPrediction predict( uint64_t address, BranchType type, int64_t knownOffset, bool isLoop = false) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program - * order */ + * order. */ virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) = 0; @@ -65,7 +65,7 @@ class BranchPredictor { * via the instruction address. Branches must be flushed in reverse * program order (though, if a block of n instructions is being flushed at * once, the exact order that the individual instructions within this block - * are flushed does not matter so long as they are all flushed) */ + * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; }; diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 4b16aad1c8..f029bbc7c7 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -28,13 +28,12 @@ class GenericPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. Optional - * arguments of getPrediction and pastDirection for use in the event that a - * new prediction is not required from the BP for a branch (e.g., if the - * fetch unit has identified the branch as being a part of a loop and so is - * reusing a previous prediction). If no prediction is required, then the - * direction prediction that is being used in lieu of a new prediction must - * be provided as an argument to predict. */ + * known. Returns a branch direction and branch target address. There is + * also an optional boolean argument for whether or not the branch has + * been identified as being a part of a loop. If the branch is a loop + * branch, then the fetch unit will reuse a previous prediction and so no + * new prediction is required. Therefore, predict() returns only a dummy + * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, bool isLoop = false) override; diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 091f5261b0..efa96ef519 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -31,13 +31,12 @@ class PerceptronPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. Optional - * arguments of getPrediction and pastDirection for use in the event that a - * new prediction is not required from the BP for a branch (e.g., if the - * fetch unit has identified the branch as being a part of a loop and so is - * reusing a previous prediction). If no prediction is required, then the - * direction prediction that is being used in lieu of a new prediction must - * be provided as an argument to predict. */ + * known. Returns a branch direction and branch target address. There is + * also an optional boolean argument for whether or not the branch has + * been identified as being a part of a loop. If the branch is a loop + * branch, then the fetch unit will reuse a previous prediction and so no + * new prediction is required. Therefore, predict() returns only a dummy + * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, bool isLoop = false) override; diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index c5a7383b4f..035942caac 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -122,7 +122,7 @@ class FetchUnit { uint16_t bufferedBytes_ = 0; /** The number of branch instructions that were executed. */ - uint64_t branchesExecuted_ = 0; + uint64_t branchesFetched_ = 0; /** Let the following PipelineFetchUnitTest derived classes be a friend of * this class to allow proper testing of 'tick' function. */ diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index b6459935ed..342355eaf2 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -75,6 +75,8 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } + /** flush branches in the buffer from the branch predictor, where the + * buffer contains microops */ void flushBranchMicroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& uop = getTailSlots()[slot]; @@ -88,6 +90,8 @@ class PipelineBuffer { } } + /** flush branches in the buffer from the branch predictor, where the + * buffer contains macroops */ void flushBranchMacroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& macroOp = getTailSlots()[slot]; diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index f4f5d0548b..d09408d136 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -28,8 +28,8 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - // Set dummy lastFtqEntry value, needed to ensure that non-prediction - // getting predict() calls in tests work. + // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() + // calls in tests work. lastFtqEntry_ = {true, 0}; } @@ -50,14 +50,15 @@ BranchPrediction GenericPredictor::predict( uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - // If a branch prediction is not required, then we can avoid a lot of the - // logic, and just determine the direction, and add the branch to the ftq + // If branch is in a loop then a new prediction is not required. Just need + // to update ftq and global history if (isLoop) { // Add branch to the back of the ftq ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | lastFtqEntry_.first) & globalHistoryMask_; + // prediction not required so return dummy prediction return {false, 0}; } diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 69fc803c40..1f5a62d229 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -23,8 +23,8 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - // Set dummy lastFtqEntry value, needed to ensure that non-prediction - // getting predict() calls in tests work. + // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() + // calls in tests work. lastFtqEntry_ = {1, 0}; } @@ -37,11 +37,11 @@ PerceptronPredictor::~PerceptronPredictor() { BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop) { - // If no prediction required, add branch to ftq and return dummy - // prediction, which will not be used by the fetch unit + // If branch is in a loop then a new prediction is not required. Just need + // to update ftq and global history if (isLoop) { // Add branch to the ftq using the past dot product in lieu of a new - // prediction. Because the loop buffer only supplies if there have been + // prediction. Because the loop buffer supplies only if there have been // no branch instructions since the branch defining the loop, we know // that the past dot product is the one most recently added to the ftq_ ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 2a48b27cba..37504adafd 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -58,7 +58,7 @@ void FetchUnit::tick() { branchPredictor_.predict(macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset(), true); - branchesExecuted_++; + branchesFetched_++; } // Cycle queue by moving front entry to back @@ -153,7 +153,7 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { prediction = branchPredictor_.predict(pc_, macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); - branchesExecuted_++; + branchesFetched_++; macroOp[0]->setBranchPrediction(prediction); } @@ -278,7 +278,7 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } -uint64_t FetchUnit::getBranchFetchedCount() const { return branchesExecuted_; } +uint64_t FetchUnit::getBranchFetchedCount() const { return branchesFetched_; } } // namespace pipeline } // namespace simeng From dbf5638557f798e6cb5903b8599e59695f623676 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:09:03 +0100 Subject: [PATCH 043/191] rebase --- .../simeng/branchpredictors/AlwaysNotTakenPredictor.hh | 3 +-- src/include/simeng/branchpredictors/BranchPredictor.hh | 6 +++--- src/include/simeng/branchpredictors/GenericPredictor.hh | 4 ++-- .../simeng/branchpredictors/PerceptronPredictor.hh | 6 +++--- src/lib/branchpredictors/GenericPredictor.cc | 9 ++++----- src/lib/branchpredictors/PerceptronPredictor.cc | 6 ++---- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index d057027db5..cbab63f0c3 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -11,8 +11,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset, - bool isLoop = false) override; + int64_t knownOffset, bool isLoop = false) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index da6d486de7..fe5aa077b9 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -51,9 +51,9 @@ class BranchPredictor { * boolean argument for if the branch is a part of a loop, in which case * the fetch unit does not require a new prediction and so only a dummy * prediction is returned. */ - virtual BranchPrediction predict( - uint64_t address, BranchType type, int64_t knownOffset, - bool isLoop = false) = 0; + virtual BranchPrediction predict(uint64_t address, BranchType type, + int64_t knownOffset, + bool isLoop = false) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index f029bbc7c7..db46df59b7 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -35,8 +35,8 @@ class GenericPredictor : public BranchPredictor { * new prediction is required. Therefore, predict() returns only a dummy * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0, + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index efa96ef519..b9b147e579 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -38,8 +38,8 @@ class PerceptronPredictor : public BranchPredictor { * new prediction is required. Therefore, predict() returns only a dummy * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0, + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in @@ -76,7 +76,7 @@ class PerceptronPredictor : public BranchPredictor { /** Keep the last ftq entry as a separate variable to be reused for loops * in the event that the ftq_ is empty by the time the next predict() is * called */ - std::pair lastFtqEntry_; + std::pair lastFtqEntry_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. Each bit represents a branch taken (1) or not diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index d09408d136..16ddfafe5e 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -40,9 +40,8 @@ GenericPredictor::~GenericPredictor() { ftq_.clear(); } -BranchPrediction GenericPredictor::predict( - uint64_t address, BranchType type, int64_t knownOffset, - bool isLoop) { +BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, + int64_t knownOffset, bool isLoop) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -56,8 +55,8 @@ BranchPrediction GenericPredictor::predict( // Add branch to the back of the ftq ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | lastFtqEntry_.first) & - globalHistoryMask_; + globalHistory_ = + ((globalHistory_ << 1) | lastFtqEntry_.first) & globalHistoryMask_; // prediction not required so return dummy prediction return {false, 0}; } diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 1f5a62d229..3ed2f2844e 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -46,9 +46,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // that the past dot product is the one most recently added to the ftq_ ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); // Update global history - globalHistory_ = - ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & - globalHistoryMask_; + globalHistory_ = ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & + globalHistoryMask_; // Return dummy prediction return {false, 0}; } @@ -127,7 +126,6 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); - std::vector perceptron = btb_[hashedIndex].first; // Work out the most recent prediction From 090e9db975d964a420c55aefe1df5041b0b78af0 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 16:12:21 +0100 Subject: [PATCH 044/191] clang format --- test/unit/pipeline/FetchUnitTest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 79092d2e5e..f15b0ecedc 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -279,8 +279,8 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff, false)).WillOnce - (Return(pred)); + EXPECT_CALL(predictor, predict(20, bType, knownOff, false)) + .WillOnce(Return(pred)); fetchUnit.tick(); // Ensure on next tick, predecode is not called From 3013198db50d5e1c0b090afe979d2c45f1fb3300 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 16:35:11 +0100 Subject: [PATCH 045/191] adding flush asserts --- .../simeng/branchpredictors/GenericPredictor.hh | 1 + .../simeng/branchpredictors/PerceptronPredictor.hh | 1 + src/lib/branchpredictors/GenericPredictor.cc | 4 +++- src/lib/branchpredictors/PerceptronPredictor.cc | 11 +++++++++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index db46df59b7..d831b1c0a1 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index b9b147e579..9a00fcfb39 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 16ddfafe5e..ef42abd3f0 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -151,7 +151,9 @@ void GenericPredictor::flush(uint64_t address) { rasHistory_.erase(it); } - // If possible, pop instruction from FTQ + assert((ftq_.size() > 0) && + "Cannot flush instruction from Branch Predictor " + "when the ftq is empty"); ftq_.pop_back(); // Roll back global history diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 3ed2f2844e..1f39a35719 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -10,6 +10,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Build BTB based on config options uint32_t btbSize = (1 << btbBits_); btb_.resize(btbSize); + // Initialise perceptron values with 0 for the global history weights, and 1 // for the bias weight; and initialise the target with 0 (i.e., unknown) for (uint32_t i = 0; i < btbSize; i++) { @@ -37,17 +38,19 @@ PerceptronPredictor::~PerceptronPredictor() { BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop) { - // If branch is in a loop then a new prediction is not required. Just need + // If branch is in a loop then a new prediction is not required. Just need // to update ftq and global history if (isLoop) { // Add branch to the ftq using the past dot product in lieu of a new - // prediction. Because the loop buffer supplies only if there have been + // prediction. Because the loop buffer supplies only if there have been // no branch instructions since the branch defining the loop, we know // that the past dot product is the one most recently added to the ftq_ ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); + // Update global history globalHistory_ = ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & globalHistoryMask_; + // Return dummy prediction return {false, 0}; } @@ -65,6 +68,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Get dot product of perceptron and history int64_t Pout = getDotProduct(perceptron, globalHistory_); + // Determine direction prediction based on its sign bool direction = (Pout >= 0); @@ -186,6 +190,9 @@ void PerceptronPredictor::flush(uint64_t address) { rasHistory_.erase(it); } + assert((ftq_.size() > 0) && + "Cannot flush instruction from Branch Predictor " + "when the ftq is empty"); ftq_.pop_back(); // Roll back global history From 594052ae804f89349d0170950f71d407fe76e313 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 12:30:35 +0100 Subject: [PATCH 046/191] Responding to PR comments --- .../branchpredictors/PerceptronPredictor.hh | 5 ++- src/lib/models/outoforder/Core.cc | 41 ++++--------------- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 9a00fcfb39..7034fe9201 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -71,7 +71,10 @@ class PerceptronPredictor : public BranchPredictor { /** Fetch Target Queue containing the dot product of the perceptron and the * global history; and the global history, both at the time of prediction, - * for each of the branches that are currently unresolved. */ + * for each of the branch instructions that are currently unresolved. The dot + * product represents the confidence of the perceptrons direction + * prediction and is needed for a correct update when the branch + * instruction is resolved. */ std::deque> ftq_; /** Keep the last ftq entry as a separate variable to be reused for loops diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 2cb1b28be4..ff95e94275 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -259,8 +259,8 @@ void Core::raiseException(const std::shared_ptr& instruction) { } void Core::handleException() { - // Check the buffer entries to see if they are branch instructions. If so, - // flush them from the BP + // Check for branch instructions in buffer, and flush them from the BP. + // Then empty the buffers fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); @@ -343,31 +343,15 @@ void Core::flushIfNeeded() { targetAddress = reorderBuffer_.getFlushAddress(); } + // Check for branch instructions in buffer, and flush them from the BP. + // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { - auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - } + fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { - auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - uop = decodeToRenameBuffer_.getHeadSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - } + decodeToRenameBuffer_.flushBranchMicroOps(predictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -389,18 +373,11 @@ void Core::flushIfNeeded() { // Update PC and wipe Fetch/Decode buffer. targetAddress = decodeUnit_.getFlushAddress(); + // Check for branch instructions in buffer, and flush them from the BP. + // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { - auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - } + fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); From 38bec68bbb1c733e07b5f65698aea24cfc95e044 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 13:00:58 +0100 Subject: [PATCH 047/191] Responding to PR comments --- src/include/simeng/pipeline/FetchUnit.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 7 ++++--- src/lib/models/outoforder/Core.cc | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index 035942caac..0eebb3c6b9 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -121,7 +121,7 @@ class FetchUnit { /** The amount of data currently in the fetch buffer. */ uint16_t bufferedBytes_ = 0; - /** The number of branch instructions that were executed. */ + /** The number of branch instructions that were fetched. */ uint64_t branchesFetched_ = 0; /** Let the following PipelineFetchUnitTest derived classes be a friend of diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index ef42abd3f0..d6298c8cb6 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -22,9 +22,10 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // Create branch prediction structures btb_ = std::vector>(1 << btbBits_, {satCntVal, 0}); - // Alter globalHistoryLength_ value to better suit required format in update() - // Multiply original globalHistoryLength_ by two so that extra branch - // outcomes are stored to allow rolling back the speculatively updated + + // Generate a bitmask that is used to ensure only the relevant number of + // bits are stored in the global history. This is two times the + // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index ff95e94275..3c7acb3c42 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -269,6 +269,8 @@ void Core::handleException() { decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); + // instructions in this buffer are already accounted for in the ROB so no + // need to check for branch instructions in this buffer renameToDispatchBuffer_.fill(nullptr); renameToDispatchBuffer_.stall(false); From 50a378ce78fba5d7418d94fe087f422db58ff3f0 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 16:29:11 +0100 Subject: [PATCH 048/191] Moving words around --- docs/sphinx/developer/components/branchPred.rst | 4 ++-- src/lib/branchpredictors/PerceptronPredictor.cc | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 767fd1bead..359682b80f 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 1f39a35719..40a22dae7f 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -22,6 +22,10 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Set up training threshold according to empirically determined formula trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); + // Generate a bitmask that is used to ensure only the relevant number of + // bits are stored in the global history. This is two times the + // globalHistoryLength_ to allow rolling back of the speculatively updated + // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() From d66e380e8daa27d6d6f62e6bcd1a20a9a420c39b Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 16:30:45 +0100 Subject: [PATCH 049/191] Moving words around --- src/lib/models/outoforder/Core.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 3c7acb3c42..4d58152b5b 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -269,7 +269,7 @@ void Core::handleException() { decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); - // instructions in this buffer are already accounted for in the ROB so no + // Instructions in this buffer are already accounted for in the ROB so no // need to check for branch instructions in this buffer renameToDispatchBuffer_.fill(nullptr); renameToDispatchBuffer_.stall(false); From a47cae2edc2549bf7cba742e86471b0789f7a281 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 16:31:24 +0100 Subject: [PATCH 050/191] Moving words around --- src/lib/models/outoforder/Core.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 4d58152b5b..5b90cf9994 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -357,6 +357,8 @@ void Core::flushIfNeeded() { decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); + // Instructions in this buffer are already accounted for in the ROB so no + // need to check for branch instructions in this buffer renameToDispatchBuffer_.fill(nullptr); renameToDispatchBuffer_.stall(false); From 02f70d878567bf4242fa05a4a6c6ae1c1bbc4f2a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Sun, 12 May 2024 14:10:54 +0100 Subject: [PATCH 051/191] Correcting definition of 'misprediction', and updating tests accordingly --- src/include/simeng/Instruction.hh | 4 ++-- test/unit/pipeline/ReorderBufferTest.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 28824aa05f..d202565ab9 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -156,8 +156,8 @@ class Instruction { "Branch misprediction check requires instruction to have executed"); // Flag as mispredicted if taken state was wrongly predicted, or taken // and predicted target is wrong - return (branchTaken_ != prediction_.isTaken || - (prediction_.target != branchAddress_)); + return ((branchTaken_ != prediction_.isTaken) || + (branchTaken_ && (prediction_.target != branchAddress_))); } /** Check whether an exception has been encountered while processing this diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index aa59fe0448..3514e583f3 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -438,7 +438,7 @@ TEST_F(ReorderBufferTest, branch) { EXPECT_EQ(loopBoundaryAddr, insnAddr); // Check that branch misprediction metrics have been correctly collected - EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); + EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 4); } // Tests that only those destination registers which have been renamed are From 081d12f70372309ecaad84500052c2868444cbff Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 13 May 2024 13:15:45 +0100 Subject: [PATCH 052/191] undoing last push --- src/include/simeng/Instruction.hh | 2 +- test/unit/pipeline/ReorderBufferTest.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index d202565ab9..d2b85068e0 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -157,7 +157,7 @@ class Instruction { // Flag as mispredicted if taken state was wrongly predicted, or taken // and predicted target is wrong return ((branchTaken_ != prediction_.isTaken) || - (branchTaken_ && (prediction_.target != branchAddress_))); + (prediction_.target != branchAddress_)); } /** Check whether an exception has been encountered while processing this diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 3514e583f3..aa59fe0448 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -438,7 +438,7 @@ TEST_F(ReorderBufferTest, branch) { EXPECT_EQ(loopBoundaryAddr, insnAddr); // Check that branch misprediction metrics have been correctly collected - EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 4); + EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); } // Tests that only those destination registers which have been renamed are From 0f2eaa87ca25f95c39fe4ef8b08a0ae7a30b6e8c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 14 May 2024 10:52:16 +0100 Subject: [PATCH 053/191] Finessing update logic re target adresses --- src/include/simeng/Instruction.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 5 ++++- src/lib/branchpredictors/PerceptronPredictor.cc | 4 +++- src/lib/pipeline/FetchUnit.cc | 8 ++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index d2b85068e0..6bdeb1e401 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -178,7 +178,7 @@ class Instruction { * executing it. */ uint16_t getStallCycles() const { return stallCycles_; } - /** Retrieve the number of cycles this instruction will take to be prcoessed + /** Retrieve the number of cycles this instruction will take to be processed * by the LSQ. */ uint16_t getLSQLatency() const { return lsqExecutionLatency_; } diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index d6298c8cb6..b8dae30339 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -120,7 +120,10 @@ void GenericPredictor::update(uint64_t address, bool isTaken, } // Update BTB entry - btb_[hashedIndex] = {satCntVal, targetAddress}; + btb_[hashedIndex].first = satCntVal; + if (isTaken) { + btb_[hashedIndex].second = targetAddress; + } // Update global history if prediction was incorrect if (prevPrediction != isTaken) { diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 40a22dae7f..150947ce47 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -164,7 +164,9 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, } btb_[hashedIndex].first = perceptron; - btb_[hashedIndex].second = targetAddress; + if (isTaken) { + btb_[hashedIndex].second = targetAddress; + } // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 37504adafd..70e2e039df 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -194,12 +194,12 @@ void FetchUnit::tick() { bufferOffset += bytesRead; bufferedBytes_ -= bytesRead; - if (!prediction.isTaken) { - // Predicted as not taken; increment PC to next instruction - pc_ += bytesRead; - } else { + if (prediction.isTaken) { // Predicted as taken; set PC to predicted target address pc_ = prediction.target; + } else { + // Predicted as not taken; increment PC to next instruction + pc_ += bytesRead; } if (pc_ >= programByteLength_) { From 2c00eaffa8a5477b2df723b4d6c3cd9ad9c06a39 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:10:57 +0100 Subject: [PATCH 054/191] Updating predict() comment in BranchPredictor.hh --- .../simeng/branchpredictors/BranchPredictor.hh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index fe5aa077b9..85c2e9c7cc 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -46,11 +46,14 @@ class BranchPredictor { public: virtual ~BranchPredictor(){}; - /** Generate a branch prediction for the specified instruction address with a - * branch type and possible known branch offset. There is an optional - * boolean argument for if the branch is a part of a loop, in which case - * the fetch unit does not require a new prediction and so only a dummy - * prediction is returned. */ + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset; defaults to 0 meaning offset is not + * known. Returns a branch direction and branch target address. There is + * also an optional boolean argument for whether or not the branch has + * been identified as being a part of a loop. If the branch is a loop + * branch, then the fetch unit will reuse a previous prediction and so no + * new prediction is required. Therefore, predict() returns only a dummy + * prediction. */ virtual BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop = false) = 0; From 190850026a7f74a7c6a21b519c714d249b435c1e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:13:30 +0100 Subject: [PATCH 055/191] Updating predict() comment in BranchPredictor.hh --- src/include/simeng/branchpredictors/BranchPredictor.hh | 6 +++--- src/include/simeng/branchpredictors/GenericPredictor.hh | 8 +++++--- .../simeng/branchpredictors/PerceptronPredictor.hh | 8 +++++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 85c2e9c7cc..ad8cf335fa 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -58,9 +58,9 @@ class BranchPredictor { int64_t knownOffset, bool isLoop = false) = 0; - /** Provide branch results to update the prediction model for the specified - * instruction address. Update must be called on instructions in program - * order. */ + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on branches in + * program order. */ virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) = 0; diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index d831b1c0a1..fdf617a59d 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -45,9 +45,11 @@ class GenericPredictor : public BranchPredictor { void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Flushes the most recently predicted branch from the BP. Address is - * required to ensure that only the correct branch is removed from the RAS. - * */ + /** Provides flushing behaviour for the implemented branch prediction schemes + * via the instruction address. Branches must be flushed in reverse + * program order (though, if a block of n instructions is being flushed at + * once, the exact order that the individual instructions within this block + * are flushed does not matter so long as they are all flushed). */ void flush(uint64_t address) override; private: diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 7034fe9201..6a7df13976 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -48,9 +48,11 @@ class PerceptronPredictor : public BranchPredictor { void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Flushes the most recently predicted branch from the BP. Address is - * required to ensure that only the correct branch is removed from the RAS. - * */ + /** Provides flushing behaviour for the implemented branch prediction schemes + * via the instruction address. Branches must be flushed in reverse + * program order (though, if a block of n instructions is being flushed at + * once, the exact order that the individual instructions within this block + * are flushed does not matter so long as they are all flushed). */ void flush(uint64_t address) override; private: From c2cccb6b89dd536d773c7ebde557689a3e6a709c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:17:35 +0100 Subject: [PATCH 056/191] Updating haeders and comments --- src/include/simeng/pipeline/ExecuteUnit.hh | 1 - src/include/simeng/pipeline/PipelineBuffer.hh | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index 450ad4b384..cd11eb23d6 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -4,7 +4,6 @@ #include #include "simeng/Instruction.hh" -#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/pipeline/PipelineBuffer.hh" namespace simeng { diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index 342355eaf2..bd7c565735 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -75,8 +75,8 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } - /** flush branches in the buffer from the branch predictor, where the - * buffer contains microops */ + /** Flush branches in the buffer from the branch predictor, where the + * buffer contains micro-ops */ void flushBranchMicroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& uop = getTailSlots()[slot]; @@ -90,8 +90,8 @@ class PipelineBuffer { } } - /** flush branches in the buffer from the branch predictor, where the - * buffer contains macroops */ + /** Flush branches in the buffer from the branch predictor, where the + * buffer contains macro-ops */ void flushBranchMacroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& macroOp = getTailSlots()[slot]; From 22d4bd872f119517cd4cd88cecf6b64a3b8af121 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:18:34 +0100 Subject: [PATCH 057/191] Fixing indentation in CMakeLists.txt --- src/lib/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ac393b19c2..ae659e2338 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,9 +14,9 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc - branchpredictors/AlwaysNotTakenPredictor.cc - branchpredictors/GenericPredictor.cc - branchpredictors/PerceptronPredictor.cc + branchpredictors/AlwaysNotTakenPredictor.cc + branchpredictors/GenericPredictor.cc + branchpredictors/PerceptronPredictor.cc config/ModelConfig.cc kernel/Linux.cc kernel/LinuxProcess.cc From 3022658966511471b319efd2295a751db996c505 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:30:37 +0100 Subject: [PATCH 058/191] Updating metric language in Core.cc --- src/lib/models/outoforder/Core.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 5b90cf9994..1d80a99afc 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,11 +224,11 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = fetchUnit_.getBranchFetchedCount(); + uint64_t totalBranchesFetched = fetchUnit_.getBranchFetchedCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesExecuted); + static_cast(totalBranchesFetched); std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; @@ -246,7 +246,7 @@ std::map Core::getStats() const { {"issue.frontendStalls", std::to_string(frontendStalls)}, {"issue.backendStalls", std::to_string(backendStalls)}, {"issue.portBusyStalls", std::to_string(portBusyStalls)}, - {"branch.executed", std::to_string(totalBranchesExecuted)}, + {"branch.fetched", std::to_string(totalBranchesFetched)}, {"branch.mispredict", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}, {"lsq.loadViolations", From 6567c62cffe401396d3f5cc981d5d40376b429ef Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 28 May 2024 12:44:39 +0100 Subject: [PATCH 059/191] Updating variable name in Core class --- src/include/simeng/models/outoforder/Core.hh | 2 +- src/lib/models/outoforder/Core.cc | 12 ++++++------ test/unit/pipeline/FetchUnitTest.cc | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/include/simeng/models/outoforder/Core.hh b/src/include/simeng/models/outoforder/Core.hh index e7d2d5c40f..82c3de37cd 100644 --- a/src/include/simeng/models/outoforder/Core.hh +++ b/src/include/simeng/models/outoforder/Core.hh @@ -136,7 +136,7 @@ class Core : public simeng::Core { std::shared_ptr exceptionGeneratingInstruction_; /** Reference to the current branch predictor */ - BranchPredictor& predictor_; + BranchPredictor& branchPredictor_; }; } // namespace outoforder diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 1d80a99afc..459cb552e9 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -73,7 +73,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, .as()), portAllocator_(portAllocator), commitWidth_(config["Pipeline-Widths"]["Commit"].as()), - predictor_(branchPredictor) { + branchPredictor_(branchPredictor) { for (size_t i = 0; i < config["Execution-Units"].num_children(); i++) { // Create vector of blocking groups std::vector blockingGroups = {}; @@ -261,11 +261,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check for branch instructions in buffer, and flush them from the BP. // Then empty the buffers - fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); + fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - decodeToRenameBuffer_.flushBranchMicroOps(predictor_); + decodeToRenameBuffer_.flushBranchMicroOps(branchPredictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -349,11 +349,11 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); + fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - decodeToRenameBuffer_.flushBranchMicroOps(predictor_); + decodeToRenameBuffer_.flushBranchMicroOps(branchPredictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -381,7 +381,7 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); + fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index f15b0ecedc..0822e63de9 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -418,7 +418,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set the first expectation from the predictor to be true so a loop body will // be detected - EXPECT_CALL(predictor, predict(_, _, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, false)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -430,7 +430,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, false)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the From e1c91d494467aa56b96e57aec78d4eea34c4a31a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 28 May 2024 14:39:38 +0100 Subject: [PATCH 060/191] Adding assert to branch predictors to confirm that they are being updated in program order --- .../AlwaysNotTakenPredictor.hh | 10 +- .../branchpredictors/BranchPredictor.hh | 7 +- .../branchpredictors/GenericPredictor.hh | 11 +- .../branchpredictors/PerceptronPredictor.hh | 11 +- .../AlwaysNotTakenPredictor.cc | 3 +- src/lib/branchpredictors/GenericPredictor.cc | 9 +- .../branchpredictors/PerceptronPredictor.cc | 9 +- src/lib/pipeline/DecodeUnit.cc | 2 +- src/lib/pipeline/ReorderBuffer.cc | 3 +- test/unit/GenericPredictorTest.cc | 126 +++++++++--------- test/unit/MockBranchPredictor.hh | 5 +- test/unit/PerceptronPredictorTest.cc | 126 +++++++++--------- test/unit/pipeline/DecodeUnitTest.cc | 3 +- test/unit/pipeline/ReorderBufferTest.cc | 24 ++-- 14 files changed, 194 insertions(+), 155 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index cbab63f0c3..6869f2e17e 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -13,10 +13,12 @@ class AlwaysNotTakenPredictor : public BranchPredictor { BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop = false) override; - /** Provide branch results to update the prediction model for the specified - * instruction address. As this model is static, this does nothing. */ - void update(uint64_t address, bool taken, uint64_t targetAddress, - BranchType type) override; + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ + void update(uint64_t address, bool isTaken, uint64_t targetAddress, + BranchType type, uint64_t instructionId) override; /** Provide flush logic for branch prediction scheme. As there's no flush * logic for an always taken predictor, this does nothing. */ diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index ad8cf335fa..4aeeb2b97e 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -59,10 +59,11 @@ class BranchPredictor { bool isLoop = false) = 0; /** Updates appropriate predictor model objects based on the address, type and - * outcome of the branch instruction. Update must be called on branches in - * program order. */ + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, - BranchType type) = 0; + BranchType type, uint64_t instructionId) = 0; /** Provides flushing behaviour for the implemented branch prediction schemes * via the instruction address. Branches must be flushed in reverse diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index fdf617a59d..1b1fb3151e 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -40,10 +40,11 @@ class GenericPredictor : public BranchPredictor { bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and - * outcome of the branch instruction. Update must be called on branches in - * program order. */ + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, - BranchType type) override; + BranchType type, uint64_t instructionId) override; /** Provides flushing behaviour for the implemented branch prediction schemes * via the instruction address. Branches must be flushed in reverse @@ -94,6 +95,10 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; + + /** The Id of the last instruction that update was called on -- used to + * ensure that update is called in program order. */ + uint64_t lastUpdatedInstructionId = 0; }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 6a7df13976..5cc90f033a 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -43,10 +43,11 @@ class PerceptronPredictor : public BranchPredictor { bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and - * outcome of the branch instruction. Update must be called on branches in - * program order. */ + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, - BranchType type) override; + BranchType type, uint64_t instructionId) override; /** Provides flushing behaviour for the implemented branch prediction schemes * via the instruction address. Branches must be flushed in reverse @@ -110,6 +111,10 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; + + /** The Id of the last instruction that update was called on -- used to + * ensure that update is called in program order. */ + uint64_t lastUpdatedInstructionId = 0; }; } // namespace simeng diff --git a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index 847e32740e..bfe342cce5 100644 --- a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -8,7 +8,8 @@ BranchPrediction AlwaysNotTakenPredictor::predict( } void AlwaysNotTakenPredictor::update(uint64_t address, bool taken, - uint64_t targetAddress, BranchType type) {} + uint64_t targetAddress, BranchType type, + uint64_t instructionId) {} void AlwaysNotTakenPredictor::flush(uint64_t address) {} diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index b8dae30339..cc6749f0e0 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -105,7 +105,14 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, } void GenericPredictor::update(uint64_t address, bool isTaken, - uint64_t targetAddress, BranchType type) { + uint64_t targetAddress, BranchType type, + uint64_t instructionId) { + // Make sure that this function is called in program order; and then update + // the lastUpdatedInstructionId variable + assert(instructionId >= lastUpdatedInstructionId && + (lastUpdatedInstructionId = instructionId) >= 0 && + "Update not called on branch instructions in program order"); + // Get previous prediction and index calculated from the FTQ bool prevPrediction = ftq_.front().first; uint64_t hashedIndex = ftq_.front().second; diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 150947ce47..4a28894945 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -123,7 +123,14 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } void PerceptronPredictor::update(uint64_t address, bool isTaken, - uint64_t targetAddress, BranchType type) { + uint64_t targetAddress, BranchType type, + uint64_t instructionId) { + // Make sure that this function is called in program order; and then update + // the lastUpdatedInstructionId variable + assert(instructionId >= lastUpdatedInstructionId && + (lastUpdatedInstructionId = instructionId) >= 0 && + "Update not called on branch instructions in program order"); + // Retrieve the previous global history and branch direction prediction from // the front of the ftq (assumes branches are updated in program order). int64_t prevPout = ftq_.front().first; diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 8748690488..31df59fa66 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -64,7 +64,7 @@ void DecodeUnit::tick() { if (!uop->isBranch()) { // Non-branch incorrectly predicted as a branch; let the predictor know predictor_.update(uop->getInstructionAddress(), false, pc_, - uop->getBranchType()); + uop->getBranchType(), uop->getInstructionId()); } // Remove macro-operations in microOps_ buffer after macro-operation // decoded in this cycle diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 47b231e866..cf5c2c52bb 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -157,7 +157,8 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { // updates is correct) if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType()); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId()); // Update the branch misprediction counter if (uop->wasBranchMispredicted()) branchMispredicts_++; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 0c698cd276..bca76c1ca9 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -87,15 +87,15 @@ TEST_F(GenericPredictorTest, Hit) { "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 4); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); @@ -112,114 +112,114 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 6); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x7C, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 10); // Spool up second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 12); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 13); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 14); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 15); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 16); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 17); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 18); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 19); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 22); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 23); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 24); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 25); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 26); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 27); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 28); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 29); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 30); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0x7C, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 32); // Recreate second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 33); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 34); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 35); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 36); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 37); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 38); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 39); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 40); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 41); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 43); } // Test Flush of RAS functionality @@ -269,43 +269,43 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x4); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 10); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); } } // namespace simeng diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 56777c0846..2ca46d4133 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -11,8 +11,9 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(predict, BranchPrediction(uint64_t address, BranchType type, int64_t knownTarget, bool getPrediction)); - MOCK_METHOD4(update, void(uint64_t address, bool taken, - uint64_t targetAddress, BranchType type)); + MOCK_METHOD5(update, void(uint64_t address, bool taken, + uint64_t targetAddress, BranchType type, + uint64_t instructionId)); MOCK_METHOD1(flush, void(uint64_t address)); }; diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 15d6c88250..01daf80f2a 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -76,15 +76,15 @@ TEST_F(PerceptronPredictorTest, Hit) { "Global-History-Length: 1, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 4); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); @@ -100,114 +100,114 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 6); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x7C, false, 0x80, BranchType::Conditional); + predictor.update(0x7C, false, 0x80, BranchType::Conditional, 10); // Spool up second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 12); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 13); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 14); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 15); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 16); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 17); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 18); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 19); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 22); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 23); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 24); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 25); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 26); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 27); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 28); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 29); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 30); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x7C, true, 0x80, BranchType::Conditional); + predictor.update(0x7C, true, 0x80, BranchType::Conditional, 32); // Recreate second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 33); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 34); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 35); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 36); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 37); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 38); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 39); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 40); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 41); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 43); } // Test Flush of RAS functionality @@ -255,17 +255,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); // Defaults to not-taken @@ -273,27 +273,27 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // Should predict target of address + 4 EXPECT_EQ(prediction.target, 0x103); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 10); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); } } // namespace simeng diff --git a/test/unit/pipeline/DecodeUnitTest.cc b/test/unit/pipeline/DecodeUnitTest.cc index f86dbc0caf..eed1ab60ae 100644 --- a/test/unit/pipeline/DecodeUnitTest.cc +++ b/test/unit/pipeline/DecodeUnitTest.cc @@ -82,7 +82,8 @@ TEST_F(PipelineDecodeUnitTest, Flush) { EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); // Check the predictor is updated with the correct instruction address and PC - EXPECT_CALL(predictor, update(2, false, 1, BranchType::Unconditional)); + EXPECT_CALL(predictor, update(2, false, 1, BranchType::Unconditional, + uop->getInstructionId())); decodeUnit.tick(); diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index aa59fe0448..0f3bfced52 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -368,7 +368,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -376,7 +377,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -384,7 +386,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -393,7 +396,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -408,7 +412,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -416,7 +421,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -424,7 +430,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -433,7 +440,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); From 7fae8c54aa8138c8c85089c99209576a01a0f1ce Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 30 May 2024 13:54:03 +0100 Subject: [PATCH 061/191] Adding test and clang formatting --- test/unit/MockBranchPredictor.hh | 6 +-- test/unit/pipeline/FetchUnitTest.cc | 68 ++++++++++++++++++++++++- test/unit/pipeline/ReorderBufferTest.cc | 48 ++++++++--------- 3 files changed, 94 insertions(+), 28 deletions(-) diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 2ca46d4133..ad728db849 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -11,9 +11,9 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(predict, BranchPrediction(uint64_t address, BranchType type, int64_t knownTarget, bool getPrediction)); - MOCK_METHOD5(update, void(uint64_t address, bool taken, - uint64_t targetAddress, BranchType type, - uint64_t instructionId)); + MOCK_METHOD5(update, + void(uint64_t address, bool taken, uint64_t targetAddress, + BranchType type, uint64_t instructionId)); MOCK_METHOD1(flush, void(uint64_t address)); }; diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 0822e63de9..2a898cd666 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -94,7 +94,7 @@ TEST_P(PipelineFetchUnitTest, TickStalled) { EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_, _, _, _)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _, false)).Times(0); fetchUnit.tick(); @@ -745,6 +745,72 @@ TEST_P(PipelineFetchUnitTest, invalidMinBytesreadsDontComplete) { } } +// Test that the Fetch unit is correctly tallying the number of branch +// instructions fetched, and that the getBranchFetchedCount getter function +// returns the correct value +TEST_P(PipelineFetchUnitTest, branchesFetchedCountedIncorrectly) { + // Set instructions to be fetched from memory + memory::MemoryReadResult memReadResultA = { + {0x0, blockSize}, RegisterValue(0xFFFF, blockSize), 1}; + span nextBlockA = {&memReadResultA, 1}; + memory::MemoryReadResult memReadResultB = { + {0x10, blockSize}, RegisterValue(0xFFFF, blockSize), 1}; + span nextBlockB = {&memReadResultB, 1}; + EXPECT_CALL(memory, getCompletedReads()).WillRepeatedly(Return(nextBlockA)); + + ON_CALL(isa, getMaxInstructionSize()).WillByDefault(Return(insnMaxSizeBytes)); + + // Set the instructions to be returned from predecode + MacroOp mOp2 = {uopPtr2}; + ON_CALL(isa, predecode(_, _, Gt(0x8), _)) + .WillByDefault(DoAll(SetArgReferee<3>(mOp2), Return(4))); + ON_CALL(*uop2, isBranch()).WillByDefault(Return(true)); + MacroOp mOp = {uopPtr}; + ON_CALL(isa, predecode(_, _, Lt(0xC), _)) + .WillByDefault(DoAll(SetArgReferee<3>(mOp), Return(4))); + ON_CALL(*uop, isBranch()).WillByDefault(Return(false)); + EXPECT_CALL(predictor, predict(_, _, _, false)) + .WillOnce(Return(BranchPrediction({true, 0x0}))); + + // Fetch instructions from data block -- one branch instruction + for (int i = 0; i < 4; i++) { + fetchUnit.tick(); + } + + // Confirm that the correct number of fetched branches has been recorded by + // the Fetch Unit + EXPECT_EQ(fetchUnit.getBranchFetchedCount(), 1); + + // Fetch the next block of instructions from memory and change the expected + // outcome of the branch predictor + fetchUnit.requestFromPC(); + EXPECT_CALL(predictor, predict(_, _, _, false)) + .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); + + // Fetch instructions from data block -- one branch instruction + for (int i = 0; i < 4; i++) { + fetchUnit.tick(); + } + + // Confirm that the correct number of fetched branches has been recorded by + // the Fetch Unit + EXPECT_EQ(fetchUnit.getBranchFetchedCount(), 2); + + const memory::MemoryAccessTarget target = {0x10, blockSize}; + EXPECT_CALL(memory, getCompletedReads()).WillRepeatedly(Return(nextBlockB)); + EXPECT_CALL(memory, requestRead(target, _)).Times(1); + + // Fetch instructions from data block -- four branch instructions + fetchUnit.requestFromPC(); + for (int i = 0; i < 4; i++) { + fetchUnit.tick(); + } + + // Confirm that the correct number of fetched branches has been recorded by + // the Fetch Unit + EXPECT_EQ(fetchUnit.getBranchFetchedCount(), 6); +} + INSTANTIATE_TEST_SUITE_P(PipelineFetchUnitTests, PipelineFetchUnitTest, ::testing::Values(std::pair(2, 4), std::pair(4, 4))); diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 0f3bfced52..ff3b63756d 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -367,27 +367,27 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -395,9 +395,9 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -411,27 +411,27 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -439,9 +439,9 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); From c25ce4ed64099821b610d0a32d9d939aad7355b0 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:09:20 +0100 Subject: [PATCH 062/191] rebase --- .../developer/components/branchPred.rst | 4 +- .../AlwaysNotTakenPredictor.hh | 2 +- .../branchpredictors/BranchPredictor.hh | 10 +- .../branchpredictors/GenericPredictor.hh | 15 +-- .../branchpredictors/PerceptronPredictor.hh | 15 +-- src/lib/branchpredictors/GenericPredictor.cc | 19 +--- .../branchpredictors/PerceptronPredictor.cc | 25 +---- src/lib/pipeline/FetchUnit.cc | 9 +- test/unit/GenericPredictorTest.cc | 104 +++++++++--------- test/unit/MockBranchPredictor.hh | 5 +- test/unit/PerceptronPredictorTest.cc | 104 +++++++++--------- test/unit/pipeline/FetchUnitTest.cc | 14 +-- 12 files changed, 127 insertions(+), 199 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 359682b80f..28ce96ddc8 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -5,7 +5,7 @@ SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredict Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, for a branch instruction. ``update`` updates the branch predictor's prediction mechanism on the actual outcome of a branch. ``flush`` provides algorithm specific flushing functionality. -The ``predict`` function is passed an instruction address, branch type, a possible known target, and optionally whether the branch is in a loop. The branch type argument currently supports the following types: +The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: - ``Conditional`` - ``LoopClosing`` @@ -13,7 +13,7 @@ The ``predict`` function is passed an instruction address, branch type, a possib - ``SubroutineCall`` - ``Unconditional`` -The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. If the branch is a part of a loop, then only a dummy branch prediction is returned by ``predict``, as the fetch unit will reuse a previous branch prediction and so no new branch prediction is needed. +The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index 6869f2e17e..ab186223b1 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -11,7 +11,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset, bool isLoop = false) override; + int64_t knownOffset) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 4aeeb2b97e..dbfc3e96fa 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -48,15 +48,9 @@ class BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. There is - * also an optional boolean argument for whether or not the branch has - * been identified as being a part of a loop. If the branch is a loop - * branch, then the fetch unit will reuse a previous prediction and so no - * new prediction is required. Therefore, predict() returns only a dummy - * prediction. */ + * known. Returns a branch direction and branch target address. */ virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset, - bool isLoop = false) = 0; + int64_t knownOffset) = 0; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 1b1fb3151e..cb5baa0169 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -29,15 +29,9 @@ class GenericPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. There is - * also an optional boolean argument for whether or not the branch has - * been identified as being a part of a loop. If the branch is a loop - * branch, then the fetch unit will reuse a previous prediction and so no - * new prediction is required. Therefore, predict() returns only a dummy - * prediction. */ + * known. Returns a branch direction and branch target address. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -65,11 +59,6 @@ class GenericPredictor : public BranchPredictor { * history state of branches that are currently unresolved */ std::deque> ftq_; - /** Keep the last ftq entry as a separate variable to be reused for loops - * in the event that the ftq_ is empty by the time the next predict() is - * called */ - std::pair lastFtqEntry_; - /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 5cc90f033a..eea6746b8b 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -32,15 +32,9 @@ class PerceptronPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. There is - * also an optional boolean argument for whether or not the branch has - * been identified as being a part of a loop. If the branch is a loop - * branch, then the fetch unit will reuse a previous prediction and so no - * new prediction is required. Therefore, predict() returns only a dummy - * prediction. */ + * known. Returns a branch direction and branch target address. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -80,11 +74,6 @@ class PerceptronPredictor : public BranchPredictor { * instruction is resolved. */ std::deque> ftq_; - /** Keep the last ftq entry as a separate variable to be reused for loops - * in the event that the ftq_ is empty by the time the next predict() is - * called */ - std::pair lastFtqEntry_; - /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. Each bit represents a branch taken (1) or not * taken (0), with the most recent branch being the least-significant-bit */ diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index cc6749f0e0..331ea2d22f 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -28,10 +28,6 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - - // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() - // calls in tests work. - lastFtqEntry_ = {true, 0}; } GenericPredictor::~GenericPredictor() { @@ -42,7 +38,7 @@ GenericPredictor::~GenericPredictor() { } BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset, bool isLoop) { + int64_t knownOffset) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -50,18 +46,6 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - // If branch is in a loop then a new prediction is not required. Just need - // to update ftq and global history - if (isLoop) { - // Add branch to the back of the ftq - ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); - // Speculatively update the global history - globalHistory_ = - ((globalHistory_ << 1) | lastFtqEntry_.first) & globalHistoryMask_; - // prediction not required so return dummy prediction - return {false, 0}; - } - // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = @@ -95,7 +79,6 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Store the hashed index for correct hashing in update() ftq_.emplace_back(prediction.isTaken, hashedIndex); - lastFtqEntry_ = {prediction.isTaken, hashedIndex}; // Speculatively update the global history globalHistory_ = diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 4a28894945..da40cf1e00 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -27,10 +27,6 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - - // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() - // calls in tests work. - lastFtqEntry_ = {1, 0}; } PerceptronPredictor::~PerceptronPredictor() { @@ -40,25 +36,7 @@ PerceptronPredictor::~PerceptronPredictor() { } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset, - bool isLoop) { - // If branch is in a loop then a new prediction is not required. Just need - // to update ftq and global history - if (isLoop) { - // Add branch to the ftq using the past dot product in lieu of a new - // prediction. Because the loop buffer supplies only if there have been - // no branch instructions since the branch defining the loop, we know - // that the past dot product is the one most recently added to the ftq_ - ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); - - // Update global history - globalHistory_ = ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & - globalHistoryMask_; - - // Return dummy prediction - return {false, 0}; - } - + int64_t knownOffset) { // Get the hashed index for the prediction table. XOR the global history with // the non-zero bits of the address, and then keep only the btbBits_ bits of // the output to keep it in bounds of the prediction table. @@ -112,7 +90,6 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // needs to be global history and not the hashed index as hashing loses // information and the global history is required for updating perceptrons. ftq_.emplace_back(Pout, globalHistory_); - lastFtqEntry_ = {Pout, globalHistory_}; // Speculatively update the global history based on the direction // prediction being made diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 70e2e039df..f34b371c59 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -52,12 +52,9 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { - macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); - // Let the branch predictor know the prediction is being reused so that - // the FTQ can be kept up to date - branchPredictor_.predict(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset(), true); + macroOp[0]->setBranchPrediction(branchPredictor_.predict( + macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset())); branchesFetched_++; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index bca76c1ca9..de4b284df5 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -111,25 +111,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 6); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -139,25 +139,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 10); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 12); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 13); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 14); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 15); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 16); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 17); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 18); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 19); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -167,25 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 22); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 23); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 24); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 25); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 26); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 27); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 28); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 29); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 30); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -195,25 +195,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 32); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 33); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 34); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 35); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 36); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 37); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 38); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 39); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 40); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 41); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -268,17 +268,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -288,17 +288,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index ad728db849..2727e6db51 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -8,9 +8,8 @@ namespace simeng { /** Mock implementation of the `BranchPredictor` interface. */ class MockBranchPredictor : public BranchPredictor { public: - MOCK_METHOD4(predict, - BranchPrediction(uint64_t address, BranchType type, - int64_t knownTarget, bool getPrediction)); + MOCK_METHOD3(predict, BranchPrediction(uint64_t address, BranchType type, + int64_t knownTarget)); MOCK_METHOD5(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type, uint64_t instructionId)); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 01daf80f2a..87c3220e58 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -99,25 +99,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 6); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -127,25 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional, 10); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 12); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 13); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 14); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 15); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 16); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 17); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 18); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 19); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -155,25 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 22); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 23); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 24); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 25); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 26); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 27); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 28); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 29); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 30); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -183,25 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional, 32); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 33); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 34); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 35); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 36); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 37); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 38); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 39); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 40); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 41); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -254,17 +254,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -276,17 +276,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 2a898cd666..2c1c99b69b 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -94,7 +94,7 @@ TEST_P(PipelineFetchUnitTest, TickStalled) { EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_, _, _, false)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _)).Times(0); fetchUnit.tick(); @@ -279,7 +279,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff, false)) + EXPECT_CALL(predictor, predict(20, bType, knownOff)) .WillOnce(Return(pred)); fetchUnit.tick(); @@ -326,7 +326,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { // Set the expectation from the predictor to be true so a loop body will // be detected - ON_CALL(predictor, predict(_, _, _, _)) + ON_CALL(predictor, predict(_, _, _)) .WillByDefault(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -418,7 +418,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set the first expectation from the predictor to be true so a loop body will // be detected - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -430,7 +430,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the @@ -769,7 +769,7 @@ TEST_P(PipelineFetchUnitTest, branchesFetchedCountedIncorrectly) { ON_CALL(isa, predecode(_, _, Lt(0xC), _)) .WillByDefault(DoAll(SetArgReferee<3>(mOp), Return(4))); ON_CALL(*uop, isBranch()).WillByDefault(Return(false)); - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Fetch instructions from data block -- one branch instruction @@ -784,7 +784,7 @@ TEST_P(PipelineFetchUnitTest, branchesFetchedCountedIncorrectly) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Fetch instructions from data block -- one branch instruction From 5f7e5a5b259acfad7692bfb1d2745f8dc7b6cd83 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:49:01 +0100 Subject: [PATCH 063/191] Adding better comments to speculativeGlobalHistory tests in generic and perceptrons predictor tests --- test/unit/GenericPredictorTest.cc | 80 +++++++++++++------------- test/unit/PerceptronPredictorTest.cc | 84 ++++++++++++++-------------- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index de4b284df5..a47957bab1 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -263,49 +263,51 @@ TEST_F(GenericPredictorTest, flush) { // Test that update correctly corrects the speculatively updated global history TEST_F(GenericPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {BTB-Tag-Bits: 2, Saturating-Count-Bits: 6, " + "{Branch-Predictor: {BTB-Tag-Bits: 6, Saturating-Count-Bits: 2, " "Global-History-Length: 6, RAS-entries: 10, Fallback-Static-Predictor: " "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); - // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 5); - // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.isTaken); - EXPECT_EQ(prediction.target, 0x4); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); + BranchPrediction pred; - // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 12); - // Ensure default behaviour for first encounter - prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.isTaken); - EXPECT_EQ(prediction.target, 0xAB); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); + // Set up the target prediction for btb entry 000111 to be 65536. No other + // target predictions will be set during this test, so we can confirm that + // we are accessing this btb entry by on the basis of this target prediction + pred = predictor.predict(28, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set + predictor.update(28, true, 65536, BranchType::Conditional, 0); + + // Set up a speculative global history of 111111 on the basis of predictions + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + + // Get prediction for address 224 to access btb entry 000111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + // Confirm prediction target is 65536 + EXPECT_EQ(pred.target, 65536); + EXPECT_TRUE(pred.isTaken); + + // Now correct the speculative global history using updates + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + + // Now a prediction for address 0 should access btb entry 000111 + pred = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_EQ(pred.target, 65536); } } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 87c3220e58..5978a02d42 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -247,53 +247,53 @@ TEST_F(PerceptronPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } -// Test that update correctly corrects the speculatively updated gloabl history +// Test that update corrects the speculatively updated global history TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 2, " + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 6, " "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); - // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 5); - // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - // Defaults to not-taken - EXPECT_FALSE(prediction.isTaken); - // Should predict target of address + 4 - EXPECT_EQ(prediction.target, 0x103); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); + BranchPrediction pred; - // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 12); - // Ensure prediction is correct with new target address - prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.isTaken); - EXPECT_EQ(prediction.target, 0xAB); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); + // Set up the target prediction for btb entry 000111 to be 65536. No other + // target predictions will be set during this test, so we can confirm that + // we are accessing this btb entry by on the basis of this target prediction + pred = predictor.predict(28, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set + predictor.update(28, true, 65536, BranchType::Conditional, 0); + + // Set up a speculative global history of 111111 on the basis of predictions + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + + // Get prediction for address 224 to access btb entry 000111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + // Confirm prediction target is 65536 + EXPECT_EQ(pred.target, 65536); + EXPECT_TRUE(pred.isTaken); + + // Now correct the speculative global history using updates + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + + // Now a prediction for address 0 should access btb entry 000111 + pred = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_EQ(pred.target, 65536); } } // namespace simeng From bac3123a9217df26cbc475dbbc9350b6d2f5c987 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:54:09 +0100 Subject: [PATCH 064/191] Clang format --- test/unit/GenericPredictorTest.cc | 22 +++++++++++----------- test/unit/PerceptronPredictorTest.cc | 22 +++++++++++----------- test/unit/pipeline/FetchUnitTest.cc | 3 +-- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index a47957bab1..0c627f98f7 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -273,37 +273,37 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { // target predictions will be set during this test, so we can confirm that // we are accessing this btb entry by on the basis of this target prediction pred = predictor.predict(28, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken - EXPECT_EQ(pred.target, 0); // Target prediction not yet set + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set predictor.update(28, true, 65536, BranchType::Conditional, 0); // Set up a speculative global history of 111111 on the basis of predictions - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); // Get prediction for address 224 to access btb entry 000111 - pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 // Confirm prediction target is 65536 EXPECT_EQ(pred.target, 65536); EXPECT_TRUE(pred.isTaken); // Now correct the speculative global history using updates - predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 - predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 - predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 // Now a prediction for address 0 should access btb entry 000111 pred = predictor.predict(0, BranchType::Conditional, 0); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 5978a02d42..db8c439032 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -259,37 +259,37 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // target predictions will be set during this test, so we can confirm that // we are accessing this btb entry by on the basis of this target prediction pred = predictor.predict(28, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken - EXPECT_EQ(pred.target, 0); // Target prediction not yet set + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set predictor.update(28, true, 65536, BranchType::Conditional, 0); // Set up a speculative global history of 111111 on the basis of predictions - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); // Get prediction for address 224 to access btb entry 000111 - pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 // Confirm prediction target is 65536 EXPECT_EQ(pred.target, 65536); EXPECT_TRUE(pred.isTaken); // Now correct the speculative global history using updates - predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 - predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 - predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 // Now a prediction for address 0 should access btb entry 000111 pred = predictor.predict(0, BranchType::Conditional, 0); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 2c1c99b69b..90870fb5e2 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -279,8 +279,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff)) - .WillOnce(Return(pred)); + EXPECT_CALL(predictor, predict(20, bType, knownOff)).WillOnce(Return(pred)); fetchUnit.tick(); // Ensure on next tick, predecode is not called From d02c095f6cf7bf3d810656beecf1fd14de640dc4 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:33:00 +0100 Subject: [PATCH 065/191] Changing use of prediction in loopbuffer --- src/lib/pipeline/FetchUnit.cc | 7 ++-- test/unit/PerceptronPredictorTest.cc | 53 ++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index f34b371c59..c2141790f7 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -52,9 +52,12 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { - macroOp[0]->setBranchPrediction(branchPredictor_.predict( + macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset())); + macroOp[0]->getKnownOffset()); + assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && + "New prediction differts from loop buffer prediction"); branchesFetched_++; } diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index db8c439032..5b348c620e 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -257,23 +257,53 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // Set up the target prediction for btb entry 000111 to be 65536. No other // target predictions will be set during this test, so we can confirm that - // we are accessing this btb entry by on the basis of this target prediction - pred = predictor.predict(28, BranchType::Conditional, 0); + // we are accessing this btb entry by on the basis of this target + // prediction. This takes a bit more setting up than the Generic predictor + // as perceptrons are more complicated than saturating counters. + predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(0, false, 4, BranchType::Conditional, 0); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(0, false, 4, BranchType::Conditional, 1); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken - EXPECT_EQ(pred.target, 0); // Target prediction not yet set - predictor.update(28, true, 65536, BranchType::Conditional, 0); + predictor.update(0, false, 4, BranchType::Conditional, 2); // GH = 000000 + predictor.predict(28, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(28, true, 65536, BranchType::Conditional, 3); // GH = 000001 + predictor.predict(24, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(24, true, 65536, BranchType::Conditional, 4); // GH = 000011 + predictor.predict(16, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(16, true, 65536, BranchType::Conditional, 5); // GH = 000111 + predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(0, true, 65536, BranchType::Conditional, 6); // GH = 001111 + predictor.predict(32, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(32, true, 65536, BranchType::Conditional, 7); // GH = 011111 + predictor.predict(96, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(96, true, 65536, BranchType::Conditional, 8); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Should be set to taken + EXPECT_EQ(pred.target, 65536); // Should be set to 65536 + predictor.update(224, true, 65536, BranchType::Conditional, + 9); // GH = 111111 // Set up a speculative global history of 111111 on the basis of predictions - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 @@ -287,12 +317,13 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { EXPECT_TRUE(pred.isTaken); // Now correct the speculative global history using updates - predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 - predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 - predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + predictor.update(4, false, 8, BranchType::Conditional, 10); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 11); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 12); // GH = 000111 // Now a prediction for address 0 should access btb entry 000111 pred = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 65536); } From 3634a23db8718af89fe2abc41caba2ef557a0aeb Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:18:30 +0100 Subject: [PATCH 066/191] replacing = with == --- .../simeng/branchpredictors/BranchPredictor.hh | 2 +- test/unit/PerceptronPredictorTest.cc | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index dbfc3e96fa..3c0b66597a 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -20,7 +20,7 @@ struct BranchPrediction { /** Whether the branch will be taken. */ bool isTaken; - /** The branch instruction's target address. If `isTaken = false`, the value + /** The branch instruction's target address. If `isTaken == false`, the value * will be ignored. */ uint64_t target; diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 5b348c620e..7768ab0ba0 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -261,32 +261,32 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // prediction. This takes a bit more setting up than the Generic predictor // as perceptrons are more complicated than saturating counters. predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, false, 4, BranchType::Conditional, 0); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, false, 4, BranchType::Conditional, 1); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, false, 4, BranchType::Conditional, 2); // GH = 000000 + predictor.predict(28, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(28, true, 65536, BranchType::Conditional, 3); // GH = 000001 + predictor.predict(24, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(24, true, 65536, BranchType::Conditional, 4); // GH = 000011 + predictor.predict(16, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(16, true, 65536, BranchType::Conditional, 5); // GH = 000111 + predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, true, 65536, BranchType::Conditional, 6); // GH = 001111 + predictor.predict(32, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(32, true, 65536, BranchType::Conditional, 7); // GH = 011111 + predictor.predict(96, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(96, true, 65536, BranchType::Conditional, 8); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); EXPECT_TRUE(pred.isTaken); // Should be set to taken EXPECT_EQ(pred.target, 65536); // Should be set to 65536 From e8320ae2d5a3fa43c90a90f479f38e966c1b07cb Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:57:00 +0100 Subject: [PATCH 067/191] Typo fix --- src/lib/pipeline/FetchUnit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index c2141790f7..06a9478529 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -57,7 +57,7 @@ void FetchUnit::tick() { macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && - "New prediction differts from loop buffer prediction"); + "New prediction differs from loop buffer prediction"); branchesFetched_++; } From 98b2dfec1dd564b7c5dd28dfc0b82f1a202149b1 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:17:16 +0100 Subject: [PATCH 068/191] rebase --- src/include/simeng/branchpredictors/GenericPredictor.hh | 2 +- .../simeng/branchpredictors/PerceptronPredictor.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 4 ++-- src/lib/branchpredictors/PerceptronPredictor.cc | 9 +++------ src/lib/pipeline/FetchUnit.cc | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index cb5baa0169..28f2ee5a81 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -87,7 +87,7 @@ class GenericPredictor : public BranchPredictor { /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId = 0; + [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index eea6746b8b..d3392b4c90 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -103,7 +103,7 @@ class PerceptronPredictor : public BranchPredictor { /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId = 0; + [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; }; } // namespace simeng diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 331ea2d22f..a79289a62c 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -92,8 +92,8 @@ void GenericPredictor::update(uint64_t address, bool isTaken, uint64_t instructionId) { // Make sure that this function is called in program order; and then update // the lastUpdatedInstructionId variable - assert(instructionId >= lastUpdatedInstructionId && - (lastUpdatedInstructionId = instructionId) >= 0 && + assert(instructionId >= lastUpdatedInstructionId_ && + (lastUpdatedInstructionId_ = instructionId) >= 0 && "Update not called on branch instructions in program order"); // Get previous prediction and index calculated from the FTQ diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index da40cf1e00..3c5337875a 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -104,8 +104,8 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t instructionId) { // Make sure that this function is called in program order; and then update // the lastUpdatedInstructionId variable - assert(instructionId >= lastUpdatedInstructionId && - (lastUpdatedInstructionId = instructionId) >= 0 && + assert(instructionId >= lastUpdatedInstructionId_ && + (lastUpdatedInstructionId_ = instructionId) >= 0 && "Update not called on branch instructions in program order"); // Retrieve the previous global history and branch direction prediction from @@ -126,11 +126,8 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Update the perceptron if the prediction was wrong, or the dot product's // magnitude was not greater than the training threshold if ((directionPrediction != isTaken) || - (abs(prevPout) < trainingThreshold_)) { + (static_cast(std::abs(prevPout)) < trainingThreshold_)) { int8_t t = (isTaken) ? 1 : -1; - if ((directionPrediction != taken) || - (static_cast(std::abs(Pout)) < trainingThreshold_)) { - int8_t t = (taken) ? 1 : -1; for (uint64_t i = 0; i < globalHistoryLength_; i++) { int8_t xi = diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 06a9478529..4e7d90471e 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,7 +53,7 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); - BranchPrediction pred = branchPredictor_.predict( + [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && From 7455be6ad53b2f4c59a0be0025dba38ae05ec701 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:54:49 +0100 Subject: [PATCH 069/191] Hiding variables that are unused in Release behind ifndef clause --- src/include/simeng/branchpredictors/GenericPredictor.hh | 5 ++++- src/include/simeng/branchpredictors/PerceptronPredictor.hh | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 28f2ee5a81..9b9a859045 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -85,9 +85,12 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; + // This variable is used only in debug mode -- therefore hide behind ifdef +#ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; + uint64_t lastUpdatedInstructionId_ = 0; +#endif }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index d3392b4c90..305a12e80c 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -101,9 +101,12 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; + // This variable is used only in debug mode -- therefore hide behind ifdef +#ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; + uint64_t lastUpdatedInstructionId_ = 0; +#endif }; } // namespace simeng From 4b164c73b68b74b8d454a212581d79417ec25e6e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:44:10 +0100 Subject: [PATCH 070/191] Adding to branch predictor docs --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 28ce96ddc8..b22a83de78 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,7 +17,7 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the back of the ftq on ``predict``, and a single entry is removed from the front of the queue on ``update`` and from the back of the queue on ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. For instance, the perceptron predictor stores the globalHistory and confidence for each prediction, but future predictors may store alternative state. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the back of the ftq on ``predict``, and a single entry is removed from the front of the queue on ``update`` and from the back of the queue on ``flush``. Generic Predictor ----------------- From 9ed27cf9c92407a6202f7c336b4616118949c782 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:48:36 +0100 Subject: [PATCH 071/191] Changing nomenclature --- docs/sphinx/developer/components/branchPred.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index b22a83de78..348541a345 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. From a1ae60016f609068dc8e47bd58ccc3a28170779c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:50:02 +0100 Subject: [PATCH 072/191] Adding to branch predictor lastUpdatedInstructionId_ comment --- src/include/simeng/branchpredictors/GenericPredictor.hh | 3 ++- src/include/simeng/branchpredictors/PerceptronPredictor.hh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 9b9a859045..d91ae0571a 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -85,7 +85,8 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; - // This variable is used only in debug mode -- therefore hide behind ifdef + // This variable is used only in debug mode to prevent errors -- therefore + // hide behind ifdef #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 305a12e80c..5669cee043 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -101,7 +101,8 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; - // This variable is used only in debug mode -- therefore hide behind ifdef + // This variable is used only in debug mode to prevent errors -- therefore + // hide behind ifdef #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ From 01628df6ee2aa11a900e245504f0e0da9599d073 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:52:30 +0100 Subject: [PATCH 073/191] Adding comment re unused predict() call in the fetch unit --- src/lib/pipeline/FetchUnit.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 4e7d90471e..e320b881e1 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,7 +53,10 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); - [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( + // Calling predict() in order to log the branch in the branch + // predictor. However, we are reusing the prediction from the loop + // buffer so we do not use the return value from predict() + branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && From 92935d3cb3af882060a3aa5491905ce9d4a3bad3 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:58:27 +0100 Subject: [PATCH 074/191] Moving lasyUpdatedInstructionId_ to BranchPredictor.hh --- src/include/simeng/branchpredictors/BranchPredictor.hh | 9 +++++++++ src/include/simeng/branchpredictors/GenericPredictor.hh | 8 -------- .../simeng/branchpredictors/PerceptronPredictor.hh | 8 -------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 3c0b66597a..ba0eb8bb8a 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -65,6 +65,15 @@ class BranchPredictor { * once, the exact order that the individual instructions within this block * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; + + + // This variable is used only in debug mode to prevent errors -- therefore + // hide behind ifdef +#ifndef NDEBUG + /** The Id of the last instruction that update was called on -- used to + * ensure that update is called in program order. */ + uint64_t lastUpdatedInstructionId_ = 0; +#endif }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index d91ae0571a..dd00526cf3 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -84,14 +84,6 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; - - // This variable is used only in debug mode to prevent errors -- therefore - // hide behind ifdef -#ifndef NDEBUG - /** The Id of the last instruction that update was called on -- used to - * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId_ = 0; -#endif }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 5669cee043..bdde169451 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -100,14 +100,6 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; - - // This variable is used only in debug mode to prevent errors -- therefore - // hide behind ifdef -#ifndef NDEBUG - /** The Id of the last instruction that update was called on -- used to - * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId_ = 0; -#endif }; } // namespace simeng From beee5e61a9b69629af6efd29288fdcf0bad1c1f4 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:05:55 +0100 Subject: [PATCH 075/191] clang format --- src/include/simeng/branchpredictors/BranchPredictor.hh | 1 - src/lib/pipeline/FetchUnit.cc | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index ba0eb8bb8a..6b7d58f9c5 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -66,7 +66,6 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; - // This variable is used only in debug mode to prevent errors -- therefore // hide behind ifdef #ifndef NDEBUG diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index e320b881e1..8da50ac70e 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -56,9 +56,9 @@ void FetchUnit::tick() { // Calling predict() in order to log the branch in the branch // predictor. However, we are reusing the prediction from the loop // buffer so we do not use the return value from predict() - branchPredictor_.predict( - macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset()); + branchPredictor_.predict(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && "New prediction differs from loop buffer prediction"); branchesFetched_++; From 12bf83c929c60099d0f57b9b4d7b878928f03f4a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:44:53 +0100 Subject: [PATCH 076/191] Adding more detail to idndef comment in BranchPredictor.hh --- src/include/simeng/branchpredictors/BranchPredictor.hh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 6b7d58f9c5..77af36eb3b 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -66,8 +66,10 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; - // This variable is used only in debug mode to prevent errors -- therefore - // hide behind ifdef + // This variable is used only in debug mode. Hiding behind ifdef to avoid + // compiler errors. Clang throws a warning (which becomes an error) for an + // unused variable. If the [[maybe_unused]] flag is added to avoid this, + // then gcc throws an error because it does heed this flag. #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ From b06d89424b4782a4a6b00137e0dced0b079e058c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:05:35 +0100 Subject: [PATCH 077/191] Updating comments in FetchUnit.cc --- src/lib/pipeline/FetchUnit.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 8da50ac70e..f11cee1018 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -55,10 +55,11 @@ void FetchUnit::tick() { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Calling predict() in order to log the branch in the branch // predictor. However, we are reusing the prediction from the loop - // buffer so we do not use the return value from predict() - branchPredictor_.predict(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset()); + // buffer so we do not use the return value from predict() except for + // in an assert + [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( + macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && "New prediction differs from loop buffer prediction"); branchesFetched_++; From 9f39f249963a57b35e97add6045b8e6782293272 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:27:01 +0100 Subject: [PATCH 078/191] U[dating expected simulated cycles --- .jenkins/build_test_run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index 52b3a7bdab..5d075ba180 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -71,7 +71,7 @@ run () { cat run echo "" compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" - compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "8677" "simulated cycles" + compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "7496" "simulated cycles" echo "" } From cccaeaafffb332898d6d13292b089714b9980654 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:34:04 +0100 Subject: [PATCH 079/191] Adding to BP documentation --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 348541a345..c15e456bb1 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-64. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. From 16ebda67e909b94244b7779e20606d028548e32d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:55:33 +0100 Subject: [PATCH 080/191] Adding to comments to address PR comments --- src/include/simeng/branchpredictors/BranchPredictor.hh | 4 ++-- src/lib/pipeline/FetchUnit.cc | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 77af36eb3b..4bcbbec3fa 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -68,8 +68,8 @@ class BranchPredictor { // This variable is used only in debug mode. Hiding behind ifdef to avoid // compiler errors. Clang throws a warning (which becomes an error) for an - // unused variable. If the [[maybe_unused]] flag is added to avoid this, - // then gcc throws an error because it does heed this flag. + // unused variable. If the [[maybe_unused]] attribute is added to avoid this, + // then gcc throws an error because it ignores this attribute. #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index f11cee1018..364226d225 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -54,9 +54,9 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Calling predict() in order to log the branch in the branch - // predictor. However, we are reusing the prediction from the loop - // buffer so we do not use the return value from predict() except for - // in an assert + // predictor (which tracks the in flight-brnaches in the ftq). However, + // we are reusing the prediction from the loop buffer so we do not + // use the return value from predict() except for in an assert [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); From 5665da1608533f039b5b840f5e398426c1426a66 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:47:34 +0100 Subject: [PATCH 081/191] Adjusting comment explaining ifdef in BranchPredictor.hh --- .../simeng/branchpredictors/BranchPredictor.hh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 4bcbbec3fa..fceca018e2 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -66,10 +66,13 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; - // This variable is used only in debug mode. Hiding behind ifdef to avoid - // compiler errors. Clang throws a warning (which becomes an error) for an - // unused variable. If the [[maybe_unused]] attribute is added to avoid this, - // then gcc throws an error because it ignores this attribute. + /** lastUpdatedInstructionId_ is used only in debug mode. Clang throws a + * warning (which becomes an error with our cmake flags) for unused + * variables. If the [[maybe_unused]] attribute is added to avoid this, + * then gcc throws a warning (which becomes an error) because it ignores + * this attribute. Therefore, to avoid the above catch 22, this variable is + * hidden behind an ifdef such that it is declared only in debug mode; when + * it is used. */ #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ From 11326052e198b2ddfbff01d997a2bfe312776f4a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:52:01 +0100 Subject: [PATCH 082/191] Updating comment regarding maybe_unused attribute in FetchUnit.cc --- src/lib/pipeline/FetchUnit.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 364226d225..e50972ab9b 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -54,9 +54,12 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Calling predict() in order to log the branch in the branch - // predictor (which tracks the in flight-brnaches in the ftq). However, - // we are reusing the prediction from the loop buffer so we do not - // use the return value from predict() except for in an assert + // predictor. The branch needs to be logged in the branch predictor + // so that the branch predictor has the information needed to update + // itself when the branch instruction is retired. However, we are + // reusing the prediction from the loop buffer, thus we do not + // use the return value from predict() except for in an assert. + // Therefore, it is given the [[maybe_unused]] attribute. [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); From cecb89336004dc0d28505b10c03b7883fe514644 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:42:13 +0100 Subject: [PATCH 083/191] Getting rid of superfluous assert in FetchUnit.cc -- the BP works regardless of the prediction being the same as the loop buffers recycled prediction --- src/lib/pipeline/FetchUnit.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index e50972ab9b..304896cbbf 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -63,8 +63,6 @@ void FetchUnit::tick() { [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); - assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && - "New prediction differs from loop buffer prediction"); branchesFetched_++; } From 16c3f895cbfa596fa7309fdd282d2d0db6aff0e7 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:37:23 +0100 Subject: [PATCH 084/191] Making further changes to comments --- docs/sphinx/developer/components/branchPred.rst | 4 ++-- src/lib/config/ModelConfig.cc | 2 +- src/lib/pipeline/FetchUnit.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index c15e456bb1..6a03c85129 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-64. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-32. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-32. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. diff --git a/src/lib/config/ModelConfig.cc b/src/lib/config/ModelConfig.cc index 049c24d04a..6d6152ced4 100644 --- a/src/lib/config/ModelConfig.cc +++ b/src/lib/config/ModelConfig.cc @@ -514,7 +514,7 @@ void ModelConfig::setExpectations(bool isDefault) { expectations_["Branch-Predictor"].addChild( ExpectationNode::createExpectation(8, "Global-History-Length")); expectations_["Branch-Predictor"]["Global-History-Length"] - .setValueBounds(1, UINT16_MAX); + .setValueBounds(1, 32); expectations_["Branch-Predictor"].addChild( ExpectationNode::createExpectation(8, "RAS-entries")); diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 304896cbbf..f4c15880a3 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -58,7 +58,7 @@ void FetchUnit::tick() { // so that the branch predictor has the information needed to update // itself when the branch instruction is retired. However, we are // reusing the prediction from the loop buffer, thus we do not - // use the return value from predict() except for in an assert. + // use the return value from predict(). // Therefore, it is given the [[maybe_unused]] attribute. [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), From 0c50f1f465d00877607dcdd6dab724ed4130c8f1 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:45:47 +0100 Subject: [PATCH 085/191] Shortening comments --- src/lib/pipeline/FetchUnit.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index f4c15880a3..2fc13628f0 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -59,10 +59,9 @@ void FetchUnit::tick() { // itself when the branch instruction is retired. However, we are // reusing the prediction from the loop buffer, thus we do not // use the return value from predict(). - // Therefore, it is given the [[maybe_unused]] attribute. - [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( - macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset()); + branchPredictor_.predict(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset()); branchesFetched_++; } From bb38bf718f1ae9185c6f250f850eedabacc68aab Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:53:14 +0100 Subject: [PATCH 086/191] Adding branches retired statistic, and specifying how it is calculated in the docs --- docs/sphinx/user/running_simeng.rst | 3 ++- src/include/simeng/pipeline/ReorderBuffer.hh | 6 ++++++ src/lib/models/outoforder/Core.cc | 4 +++- src/lib/pipeline/ReorderBuffer.cc | 8 +++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/user/running_simeng.rst b/docs/sphinx/user/running_simeng.rst index 92a9682032..0a97fc50fe 100644 --- a/docs/sphinx/user/running_simeng.rst +++ b/docs/sphinx/user/running_simeng.rst @@ -26,7 +26,8 @@ Exit Clause The reason why the simulation has halted. Most commonly this is due to the invoking of the ``exit()`` system call by the workload under simulation. Statistics - A selection of simulation statistics describing the emergent simulated PMU-style hardware events. + A selection of simulation statistics describing the emergent simulated PMU-style hardware events. With respect to branch statistics, the misprediction rate +is calculated as branches mispredicted / branches retired. All non-workload outputs from SimEng are prefixed with a tag of the format ``[SimEng:Object]`` (e.g. ``[SimEng:ExceptionHandler]``). If the output came from the root of the framework, the ``Object`` field is omitted. diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index 64a32ce78b..df926eeca0 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -88,6 +88,9 @@ class ReorderBuffer { /** Retrieve the number of branch mispredictions. */ uint64_t getBranchMispredictedCount() const; + /** Retrieve the number of retired brancehs. */ + uint64_t getRetiredBranchesCount() const; + private: /** A reference to the register alias table. */ RegisterAliasTable& rat_; @@ -150,6 +153,9 @@ class ReorderBuffer { /** The number of branch mispredictions that were observed. */ uint64_t branchMispredicts_ = 0; + + /** The number of retired branch instructions */ + uint64_t retiredBranches_ = 0; }; } // namespace pipeline diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 459cb552e9..9db41eed15 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -225,10 +225,11 @@ std::map Core::getStats() const { auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); uint64_t totalBranchesFetched = fetchUnit_.getBranchFetchedCount(); + uint64_t totalBranchesRetired = reorderBuffer_.getRetiredBranchesCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesFetched); + static_cast(totalBranchesRetired); std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; @@ -247,6 +248,7 @@ std::map Core::getStats() const { {"issue.backendStalls", std::to_string(backendStalls)}, {"issue.portBusyStalls", std::to_string(portBusyStalls)}, {"branch.fetched", std::to_string(totalBranchesFetched)}, + {"branch.retired", std::to_string(totalBranchesRetired)}, {"branch.mispredict", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}, {"lsq.loadViolations", diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index cf5c2c52bb..5f5e042d48 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -159,7 +159,8 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType(), uop->getInstructionId()); - // Update the branch misprediction counter + // Update the branches retired and mispredicted counters + retiredBranches_++; if (uop->wasBranchMispredicted()) branchMispredicts_++; } @@ -190,6 +191,7 @@ void ReorderBuffer::flush(uint64_t afterInsnId) { // If the instruction is a branch, supply address to branch flushing logic if (uop->isBranch()) { predictor_.flush(uop->getInstructionAddress()); + } buffer_.pop_back(); } @@ -216,9 +218,13 @@ uint64_t ReorderBuffer::getInstructionsCommittedCount() const { uint64_t ReorderBuffer::getViolatingLoadsCount() const { return loadViolations_; } + uint64_t ReorderBuffer::getBranchMispredictedCount() const { return branchMispredicts_; } +uint64_t ReorderBuffer::getRetiredBranchesCount() const { + return retiredBranches_; +} } // namespace pipeline } // namespace simeng From 2c4b73915ed6a995895df26e6ded3646527da802 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:14:45 +0100 Subject: [PATCH 087/191] clang format --- src/lib/pipeline/ReorderBuffer.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 5f5e042d48..e72e6e79dc 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -191,7 +191,6 @@ void ReorderBuffer::flush(uint64_t afterInsnId) { // If the instruction is a branch, supply address to branch flushing logic if (uop->isBranch()) { predictor_.flush(uop->getInstructionAddress()); - } buffer_.pop_back(); } From 6cc094e7653bdf732c77327475c3711fcf6ce2c1 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:34:49 +0100 Subject: [PATCH 088/191] Updating output metrics --- .jenkins/build_test_run.sh | 2 +- src/lib/models/outoforder/Core.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index 5d075ba180..22ddef221a 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -70,7 +70,7 @@ run () { echo "Simulation with configuration file argument:" cat run echo "" - compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" + compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "1392" "retired instructions" compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "7496" "simulated cycles" echo "" } diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 9db41eed15..59774eeaaf 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -249,7 +249,7 @@ std::map Core::getStats() const { {"issue.portBusyStalls", std::to_string(portBusyStalls)}, {"branch.fetched", std::to_string(totalBranchesFetched)}, {"branch.retired", std::to_string(totalBranchesRetired)}, - {"branch.mispredict", std::to_string(totalBranchMispredicts)}, + {"branch.mispredicted", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}, {"lsq.loadViolations", std::to_string(reorderBuffer_.getViolatingLoadsCount())}}; From 1c394e791a37e83ad97c48d9ad0009ec9635815d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:37:20 +0100 Subject: [PATCH 089/191] Fixing LoopBuffer bug (#421) * Updating how a LoopBuffer is begun; and correcting how branch mispredicts are calculated * Adding comments to explain bug fix in FetchUnit.cc * Adding comments to explain bug fix in FetchUnit.cc * Adding comments to explain bug fix in FetchUnit.cc * Adding comments to explain bug fix in FetchUnit.cc * Updating simulated cycles * Updating comments --- .jenkins/build_test_run.sh | 2 +- src/include/simeng/Instruction.hh | 2 +- src/lib/pipeline/FetchUnit.cc | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index 52b3a7bdab..22e48655c9 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -71,7 +71,7 @@ run () { cat run echo "" compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" - compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "8677" "simulated cycles" + compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "8612" "simulated cycles" echo "" } diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 9a126460de..0fbaa932d5 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -157,7 +157,7 @@ class Instruction { // Flag as mispredicted if taken state was wrongly predicted, or taken and // predicted target is wrong return (branchTaken_ != prediction_.taken || - (prediction_.target != branchAddress_)); + (branchTaken_ && (prediction_.target != branchAddress_))); } /** Check whether an exception has been encountered while processing this diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 553c8198f4..7bc59051e9 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -176,8 +176,17 @@ void FetchUnit::tick() { } } else if (loopBufferState_ == LoopBufferState::WAITING && pc_ == loopBoundaryAddress_) { - // Once set loopBoundaryAddress_ is fetched, start to fill loop buffer - loopBufferState_ = LoopBufferState::FILLING; + // loopBoundaryAddress_ has been fetched whilst loop buffer is waiting, + // start filling Loop Buffer if the branch predictor tells us to + // reenter the detected loop + if (macroOp[0]->isBranch() && !macroOp[0]->getBranchPrediction().taken) { + // If branch is not taken then we aren't re-entering the detected + // loop, therefore Loop Buffer stays idle + loopBufferState_ = LoopBufferState::IDLE; + } else { + // Otherwise, start to fill Loop Buffer + loopBufferState_ = LoopBufferState::FILLING; + } } assert(bytesRead <= bufferedBytes_ && From f86cf1ed38a30bd5292d29b1a0a7c74bab199db5 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:05:33 +0000 Subject: [PATCH 090/191] Adding speculative global history, moving update to ROB, and replacing BTBHistory with FTQ --- src/include/simeng/BranchPredictor.hh | 7 +++ src/include/simeng/GenericPredictor.hh | 4 +- src/include/simeng/PerceptronPredictor.hh | 6 +- src/include/simeng/models/outoforder/Core.hh | 3 + src/include/simeng/pipeline/ExecuteUnit.hh | 7 +-- src/lib/GenericPredictor.cc | 29 +++++++-- src/lib/PerceptronPredictor.cc | 31 ++++++++-- src/lib/models/inorder/Core.cc | 2 +- src/lib/models/outoforder/Core.cc | 62 +++++++++++++++++++- src/lib/pipeline/DecodeUnit.cc | 7 ++- src/lib/pipeline/ExecuteUnit.cc | 9 +-- src/lib/pipeline/FetchUnit.cc | 1 + src/lib/pipeline/ReorderBuffer.cc | 6 ++ test/unit/MockBranchPredictor.hh | 1 + test/unit/pipeline/ExecuteUnitTest.cc | 2 +- 15 files changed, 145 insertions(+), 32 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 8e2ddd0797..1f58f5938f 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -60,6 +60,13 @@ class BranchPredictor { * via the instruction address. */ virtual void flush(uint64_t address) = 0; + + virtual void addToFTQ(uint64_t address) = 0; + + + uint64_t pre = 0; + uint64_t upd = 0; + uint64_t flu = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 28e7ccbaac..697e1dc5b1 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,6 +40,8 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + void addToFTQ(uint64_t address) override; + private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ uint8_t btbBits_; @@ -49,7 +51,7 @@ class GenericPredictor : public BranchPredictor { std::vector> btb_; /** The previous BTB index calculated for an address. */ - std::map btbHistory_; + std::deque> FTQ_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index b76e4dd7e4..348fe37f8d 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,6 +43,8 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + void addToFTQ(uint64_t address) override; + private: /** Returns the dot product of a perceptron and a history vector. Used to * determine a direction prediction */ @@ -59,8 +61,8 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** The previous hashed index for an address. */ - std::map btbHistory_; + /** Fetch Target Queue containing the address and previous global history state of branches that are currently unresolved */ + std::deque> FTQ_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ diff --git a/src/include/simeng/models/outoforder/Core.hh b/src/include/simeng/models/outoforder/Core.hh index 2b1b16f8a0..e7d2d5c40f 100644 --- a/src/include/simeng/models/outoforder/Core.hh +++ b/src/include/simeng/models/outoforder/Core.hh @@ -134,6 +134,9 @@ class Core : public simeng::Core { /** A pointer to the instruction responsible for generating the exception. */ std::shared_ptr exceptionGeneratingInstruction_; + + /** Reference to the current branch predictor */ + BranchPredictor& predictor_; }; } // namespace outoforder diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index 14d8b47e7c..a72de10850 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -33,8 +33,7 @@ class ExecuteUnit { std::function&)> handleLoad, std::function&)> handleStore, std::function&)> raiseException, - BranchPredictor& predictor, bool pipelined = true, - const std::vector& blockingGroups = {}); + bool pipelined = true, const std::vector& blockingGroups = {}); /** Tick the execute unit. Places incoming instructions into the pipeline and * executes an instruction that has reached the head of the pipeline, if @@ -91,10 +90,6 @@ class ExecuteUnit { /** A function handle called upon exception generation. */ std::function&)> raiseException_; - /** A reference to the branch predictor, for updating with prediction results. - */ - BranchPredictor& predictor_; - /** Whether this unit is pipelined, or if all instructions should stall until * complete. */ bool pipelined_; diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 7379c661af..ebafdb997e 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -23,7 +23,7 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) btb_ = std::vector>(1 << btbBits_, {satCntVal, 0}); // Alter globalHistoryLength_ value to better suit required format in update() - globalHistoryLength_ = (1 << globalHistoryLength_) - 1; + globalHistoryLength_ = (1 << (globalHistoryLength_ * 2)) - 1; } GenericPredictor::~GenericPredictor() { @@ -37,11 +37,11 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Get index via an XOR hash between the global history and the lower btbBits_ // bits of the instruction address uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; - btbHistory_[address] = hashedIndex; + FTQ_.emplace_back(address, hashedIndex); // Get prediction from BTB bool direction = - btb_[hashedIndex].first < (1 << (satCntBits_ - 1)) ? false : true; + btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; BranchPrediction prediction = {direction, target}; @@ -70,13 +70,19 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, } else if (type == BranchType::Conditional) { if (!prediction.taken) prediction.target = address + 4; } + + globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; + return prediction; } void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { + if (FTQ_.empty() || FTQ_.front().first != address) return; + // Get previous index calculated for the instruction address supplied - uint64_t hashedIndex = btbHistory_[address]; + uint64_t hashedIndex = FTQ_.front().second; + FTQ_.pop_front(); // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; @@ -89,8 +95,11 @@ void GenericPredictor::update(uint64_t address, bool taken, // Update BTB entry btb_[hashedIndex] = {satCntVal, targetAddress}; - // Update global history value with new direction - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; + + // Update global history if prediction was incorrect + // ToDo -- consider if need to replace history rather than just remove? + if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) globalHistory_ >>= 1; + return; } @@ -115,6 +124,14 @@ void GenericPredictor::flush(uint64_t address) { } rasHistory_.erase(it); } + + if (!FTQ_.empty()) FTQ_.pop_back(); + + globalHistory_ >>= 1; +} + +void GenericPredictor::addToFTQ(uint64_t address) { + FTQ_.emplace_back(address, globalHistory_); } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 8d1202f8d6..49a84d302f 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -38,7 +38,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - btbHistory_[address] = globalHistory_; + FTQ_.emplace_back(address, globalHistory_); // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -78,13 +78,23 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } else if (type == BranchType::Conditional) { if (!prediction.taken) prediction.target = address + 4; } + + // speculatively update global history + globalHistory_ = + ((globalHistory_ << 1) | prediction.taken) & ((1 << (globalHistoryLength_ * 2)) - 1); + + pre++; return prediction; } void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { + // Make sure there is FTQ info and it relates to the correct branch + if (FTQ_.empty() || FTQ_.front().first != address) return; // Work out hash index - uint64_t prevGlobalHistory = btbHistory_[address]; + uint64_t prevGlobalHistory = FTQ_.front().second; + FTQ_.pop_front(); + uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); @@ -118,8 +128,11 @@ void PerceptronPredictor::update(uint64_t address, bool taken, btb_[hashedIndex].first = perceptron; btb_[hashedIndex].second = targetAddress; - globalHistory_ = - ((globalHistory_ << 1) | taken) & ((1 << globalHistoryLength_) - 1); + // Update global history if prediction was incorrect + // ToDo -- consider if need to replace history rather than just remove? + if (directionPrediction != taken) globalHistory_ >>= 1; + + upd++;; return; } @@ -144,6 +157,16 @@ void PerceptronPredictor::flush(uint64_t address) { } rasHistory_.erase(it); } + + if (!FTQ_.empty()) FTQ_.pop_back(); + + // Roll back global history + globalHistory_ >>= 1; + flu++; +} + +void PerceptronPredictor::addToFTQ(uint64_t address) { + FTQ_.emplace_back(address, globalHistory_); } int64_t PerceptronPredictor::getDotProduct( diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index b196d2cf8c..de6878657c 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -31,7 +31,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, [this](auto instruction) { handleLoad(instruction); }, [this](auto instruction) { storeData(instruction); }, [this](auto instruction) { raiseException(instruction); }, - branchPredictor, false), + false), writebackUnit_(completionSlots_, registerFileSet_, [](auto insnId) {}) { // Query and apply initial state auto state = isa.getInitialState(); diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 4f7cf0f42d..e697778ae5 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -72,7 +72,8 @@ Core::Core(memory::MemoryInterface& instructionMemory, config["LSQ-L1-Interface"]["Permitted-Stores-Per-Cycle"] .as()), portAllocator_(portAllocator), - commitWidth_(config["Pipeline-Widths"]["Commit"].as()) { + commitWidth_(config["Pipeline-Widths"]["Commit"].as()), + predictor_(branchPredictor) { for (size_t i = 0; i < config["Execution-Units"].num_children(); i++) { // Create vector of blocking groups std::vector blockingGroups = {}; @@ -87,7 +88,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, }, [this](auto uop) { loadStoreQueue_.startLoad(uop); }, [this](auto uop) { loadStoreQueue_.supplyStoreData(uop); }, - [](auto uop) { uop->setCommitReady(); }, branchPredictor, + [](auto uop) { uop->setCommitReady(); }, config["Execution-Units"][i]["Pipelined"].as(), blockingGroups); } // Provide reservation size getter to A64FX port allocator @@ -236,6 +237,13 @@ std::map Core::getStats() const { std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; + std::cout << "_____BRANCH STATS_____" << std::endl + << "Predictions:\t\t" << predictor_.pre << std::endl + << "Updates: \t\t" << predictor_.upd << std::endl + << "Flushes: \t\t" << predictor_.flu << std::endl + << "Delta: \t\t\t" << ((int64_t)predictor_.pre - ((int64_t)predictor_.upd + (int64_t)predictor_.flu)) << std::endl + << std::endl << std::endl; + return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, @@ -263,9 +271,29 @@ void Core::raiseException(const std::shared_ptr& instruction) { } void Core::handleException() { + for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { + auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + } fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); + for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { + auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + uop = decodeToRenameBuffer_.getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + } decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -345,9 +373,29 @@ void Core::flushIfNeeded() { fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); + for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { + auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + } fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); + for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { + auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + uop = decodeToRenameBuffer_.getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + predictor_.flush(uop->getInstructionAddress()); + } + } decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -371,6 +419,16 @@ void Core::flushIfNeeded() { fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); + for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { + auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + predictor_.flush(macroOp[0]->getInstructionAddress()); + } + } fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index cd152be942..647f24ec21 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -93,7 +93,12 @@ bool DecodeUnit::shouldFlush() const { return shouldFlush_; } uint64_t DecodeUnit::getFlushAddress() const { return pc_; } uint64_t DecodeUnit::getEarlyFlushes() const { return earlyFlushes_; } -void DecodeUnit::purgeFlushed() { microOps_.clear(); } +void DecodeUnit::purgeFlushed() { + while (!microOps_.empty()) { + if (microOps_.front()->isBranch()) predictor_.flush(microOps_.front()->getInstructionAddress()); + microOps_.pop_front(); + } +} } // namespace pipeline } // namespace simeng diff --git a/src/lib/pipeline/ExecuteUnit.cc b/src/lib/pipeline/ExecuteUnit.cc index c87c2e1845..b1b7d5fed7 100644 --- a/src/lib/pipeline/ExecuteUnit.cc +++ b/src/lib/pipeline/ExecuteUnit.cc @@ -13,15 +13,13 @@ ExecuteUnit::ExecuteUnit( std::function&)> handleLoad, std::function&)> handleStore, std::function&)> raiseException, - BranchPredictor& predictor, bool pipelined, - const std::vector& blockingGroups) + bool pipelined, const std::vector& blockingGroups) : input_(input), output_(output), forwardOperands_(forwardOperands), handleLoad_(handleLoad), handleStore_(handleStore), raiseException_(raiseException), - predictor_(predictor), pipelined_(pipelined), blockingGroups_(blockingGroups) {} @@ -140,11 +138,6 @@ void ExecuteUnit::execute(std::shared_ptr& uop) { if (uop->isBranch()) { pc_ = uop->getBranchAddress(); - - // Update branch predictor with branch results - predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), pc_, - uop->getBranchType()); - // Update the branch instruction counter branchesExecuted_++; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 7bc59051e9..f4c2703d1f 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,6 +53,7 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress()); } // Cycle queue by moving front entry to back diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 32889bf93e..19a257aa7e 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -152,6 +152,12 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { 0}; } } + + // If it is a branch, now update the predictor (here to ensure order of updates is correct + if (uop->isBranch()) { + predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); + } + buffer_.pop_front(); } diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 05868a6fed..6e8fb36aaa 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -13,6 +13,7 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type)); MOCK_METHOD1(flush, void(uint64_t address)); + MOCK_METHOD1(addToFTQ, void(uint64_t address)); }; } // namespace simeng diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index 0f82593ff6..1c6664e384 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -35,7 +35,7 @@ class PipelineExecuteUnitTest : public testing::Test { [this](auto instruction) { executionHandlers.raiseException(instruction); }, - predictor, true, {3, 4, 5}), + true, {3, 4, 5}), uop(new MockInstruction), secondUop(new MockInstruction), thirdUop(new MockInstruction), From d65f400ad781959c99ebb03f16cc7077ce2cc449 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:12:25 +0000 Subject: [PATCH 091/191] Getting rid of print statements used to track down missing branches --- src/include/simeng/BranchPredictor.hh | 5 ----- src/lib/GenericPredictor.cc | 1 + src/lib/PerceptronPredictor.cc | 5 ++--- src/lib/models/outoforder/Core.cc | 7 ------- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 1f58f5938f..145f709f0f 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -62,11 +62,6 @@ class BranchPredictor { virtual void flush(uint64_t address) = 0; virtual void addToFTQ(uint64_t address) = 0; - - - uint64_t pre = 0; - uint64_t upd = 0; - uint64_t flu = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index ebafdb997e..aa00aded4b 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -30,6 +30,7 @@ GenericPredictor::~GenericPredictor() { btb_.clear(); ras_.clear(); rasHistory_.clear(); + FTQ_.clear(); } BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 49a84d302f..56f349e8a8 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -25,6 +25,8 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) PerceptronPredictor::~PerceptronPredictor() { ras_.clear(); rasHistory_.clear(); + std::cout << "___________REMAINING FTQ OF SIZE " << FTQ_.size() << std::endl; + FTQ_.clear(); } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, @@ -83,7 +85,6 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & ((1 << (globalHistoryLength_ * 2)) - 1); - pre++; return prediction; } @@ -132,7 +133,6 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // ToDo -- consider if need to replace history rather than just remove? if (directionPrediction != taken) globalHistory_ >>= 1; - upd++;; return; } @@ -162,7 +162,6 @@ void PerceptronPredictor::flush(uint64_t address) { // Roll back global history globalHistory_ >>= 1; - flu++; } void PerceptronPredictor::addToFTQ(uint64_t address) { diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index e697778ae5..f853e9efd3 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -237,13 +237,6 @@ std::map Core::getStats() const { std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; - std::cout << "_____BRANCH STATS_____" << std::endl - << "Predictions:\t\t" << predictor_.pre << std::endl - << "Updates: \t\t" << predictor_.upd << std::endl - << "Flushes: \t\t" << predictor_.flu << std::endl - << "Delta: \t\t\t" << ((int64_t)predictor_.pre - ((int64_t)predictor_.upd + (int64_t)predictor_.flu)) << std::endl - << std::endl << std::endl; - return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, From 4773ceba805c236e9aaaeb795e4cc6662873d4af Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:16:38 +0000 Subject: [PATCH 092/191] Changing how globalHistory is updated in the event of a mispredicton --- src/lib/GenericPredictor.cc | 5 +++-- src/lib/PerceptronPredictor.cc | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index aa00aded4b..32f243fe06 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -98,8 +98,9 @@ void GenericPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect - // ToDo -- consider if need to replace history rather than just remove? - if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) globalHistory_ >>= 1; + if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { + globalHistory_ ^= (1 << FTQ_.size()); + } return; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 56f349e8a8..b119134c03 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -25,7 +25,6 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) PerceptronPredictor::~PerceptronPredictor() { ras_.clear(); rasHistory_.clear(); - std::cout << "___________REMAINING FTQ OF SIZE " << FTQ_.size() << std::endl; FTQ_.clear(); } @@ -130,8 +129,9 @@ void PerceptronPredictor::update(uint64_t address, bool taken, btb_[hashedIndex].second = targetAddress; // Update global history if prediction was incorrect - // ToDo -- consider if need to replace history rather than just remove? - if (directionPrediction != taken) globalHistory_ >>= 1; + if (directionPrediction != taken) { + globalHistory_ ^= (1 << FTQ_.size()); + } return; } From 74808b7f0bc588883339421132eabd69e9aaae40 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:30:56 +0000 Subject: [PATCH 093/191] Clang format etc. --- src/include/simeng/PerceptronPredictor.hh | 3 ++- src/lib/GenericPredictor.cc | 19 ++++++++++++------- src/lib/PerceptronPredictor.cc | 20 +++++++++++--------- src/lib/models/inorder/Core.cc | 3 +-- src/lib/pipeline/FetchUnit.cc | 2 ++ src/lib/pipeline/ReorderBuffer.cc | 6 ++++-- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 348fe37f8d..42dd697ad6 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -61,7 +61,8 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** Fetch Target Queue containing the address and previous global history state of branches that are currently unresolved */ + /** Fetch Target Queue containing the address and previous global history + * state of branches that are currently unresolved */ std::deque> FTQ_; /** An n-bit history of previous branch directions where n is equal to diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 32f243fe06..2bf2257c20 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -38,11 +38,12 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Get index via an XOR hash between the global history and the lower btbBits_ // bits of the instruction address uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + + // Store the hashed index for correct hashing in update() FTQ_.emplace_back(address, hashedIndex); // Get prediction from BTB - bool direction = - btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); + bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; BranchPrediction prediction = {direction, target}; @@ -72,16 +73,19 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, if (!prediction.taken) prediction.target = address + 4; } - globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; + // Speculatively update the global history + globalHistory_ = + ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; return prediction; } void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { + // Sanity check to avoid segfault/wrong branch update if (FTQ_.empty() || FTQ_.front().first != address) return; - // Get previous index calculated for the instruction address supplied + // Get previous index calculated from the FTQ uint64_t hashedIndex = FTQ_.front().second; FTQ_.pop_front(); @@ -96,13 +100,12 @@ void GenericPredictor::update(uint64_t address, bool taken, // Update BTB entry btb_[hashedIndex] = {satCntVal, targetAddress}; - // Update global history if prediction was incorrect if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { + // Bit-flip the global history bit corresponding to this prediction + // We know how many predictions there have since been by the size of the FTQ globalHistory_ ^= (1 << FTQ_.size()); } - - return; } void GenericPredictor::flush(uint64_t address) { @@ -127,8 +130,10 @@ void GenericPredictor::flush(uint64_t address) { rasHistory_.erase(it); } + // If possible, pop instruction from FTQ if (!FTQ_.empty()) FTQ_.pop_back(); + // Roll back global history globalHistory_ >>= 1; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index b119134c03..e35d04c38b 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -81,20 +81,22 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } // speculatively update global history - globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & ((1 << (globalHistoryLength_ * 2)) - 1); + globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & + ((1 << (globalHistoryLength_ * 2)) - 1); return prediction; } void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Make sure there is FTQ info and it relates to the correct branch + // Sanity check to avoid segfault/wrong branch update if (FTQ_.empty() || FTQ_.front().first != address) return; - // Work out hash index + + // Get previous branch state from FTQ uint64_t prevGlobalHistory = FTQ_.front().second; FTQ_.pop_front(); + // Work out hashed index uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); @@ -129,11 +131,9 @@ void PerceptronPredictor::update(uint64_t address, bool taken, btb_[hashedIndex].second = targetAddress; // Update global history if prediction was incorrect - if (directionPrediction != taken) { - globalHistory_ ^= (1 << FTQ_.size()); - } - - return; + // Bit-flip the global history bit corresponding to this prediction + // We know how many predictions there have since been by the size of the FTQ + if (directionPrediction != taken) globalHistory_ ^= (1 << FTQ_.size()); } void PerceptronPredictor::flush(uint64_t address) { @@ -158,6 +158,7 @@ void PerceptronPredictor::flush(uint64_t address) { rasHistory_.erase(it); } + // If possible, pop instruction from FTQ if (!FTQ_.empty()) FTQ_.pop_back(); // Roll back global history @@ -165,6 +166,7 @@ void PerceptronPredictor::flush(uint64_t address) { } void PerceptronPredictor::addToFTQ(uint64_t address) { + // Add instruction to the FTQ in event of reused prediction FTQ_.emplace_back(address, globalHistory_); } diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index de6878657c..16b21d2a4d 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -30,8 +30,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, [this](auto regs, auto values) { forwardOperands(regs, values); }, [this](auto instruction) { handleLoad(instruction); }, [this](auto instruction) { storeData(instruction); }, - [this](auto instruction) { raiseException(instruction); }, - false), + [this](auto instruction) { raiseException(instruction); }, false), writebackUnit_(completionSlots_, registerFileSet_, [](auto insnId) {}) { // Query and apply initial state auto state = isa.getInitialState(); diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index f4c2703d1f..3887b49dc8 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,6 +53,8 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + // Let the branch predictor know the prediction is being reused so that + // the FTQ can be kept up to date branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress()); } diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 19a257aa7e..4c89c30e66 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -153,9 +153,11 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { } } - // If it is a branch, now update the predictor (here to ensure order of updates is correct + // If it is a branch, now update the predictor (here to ensure order of + // updates is correct if (uop->isBranch()) { - predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); + predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType()); } buffer_.pop_front(); From 377b7e85fcf59d0ab727779f8cd2e9d03fe7cc66 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:38:45 +0000 Subject: [PATCH 094/191] Adding to documentation --- docs/sphinx/developer/components/branchPred.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index ba91fe98d9..6466802080 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -3,7 +3,7 @@ Branch prediction SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredictor`` class to enable speculative execution. -Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, and ``flush`` provides optional algorithm specific flushing functionality. +Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, ``flush``, and ``addToFTQ``` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, ``flush`` provides optional algorithm specific flushing functionality, and ``addToFTQ`` adds an instruction to the predictor's Fetch Target Queue (FTQ) when a new prediction is not needed. The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: @@ -23,7 +23,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. + For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -41,7 +41,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. + For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. From e9a11409393e16a604b379cbff1c5c842da1db9b Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Sat, 24 Feb 2024 18:20:18 +0000 Subject: [PATCH 095/191] Fixing global history bug in generic predictor --- src/lib/GenericPredictor.cc | 3 +- src/lib/PerceptronPredictor.cc | 5 +- test/unit/GenericPredictorTest.cc | 91 ++++++++++++++++--------- test/unit/PerceptronPredictorTest.cc | 89 +++++++++++++++--------- test/unit/pipeline/ExecuteUnitTest.cc | 13 ---- test/unit/pipeline/RenameUnitTest.cc | 2 +- test/unit/pipeline/ReorderBufferTest.cc | 16 ++--- 7 files changed, 129 insertions(+), 90 deletions(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 2bf2257c20..0d3439cab3 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -138,7 +138,8 @@ void GenericPredictor::flush(uint64_t address) { } void GenericPredictor::addToFTQ(uint64_t address) { - FTQ_.emplace_back(address, globalHistory_); + uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + FTQ_.emplace_back(address, hashedIndex); } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index e35d04c38b..38d2c9ac4b 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -90,7 +90,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { // Sanity check to avoid segfault/wrong branch update - if (FTQ_.empty() || FTQ_.front().first != address) return; + //if (FTQ_.empty() || FTQ_.front().first != address) return; // Get previous branch state from FTQ uint64_t prevGlobalHistory = FTQ_.front().second; @@ -159,7 +159,8 @@ void PerceptronPredictor::flush(uint64_t address) { } // If possible, pop instruction from FTQ - if (!FTQ_.empty()) FTQ_.pop_back(); + // if (!FTQ_.empty()) FTQ_.pop_back(); + FTQ_.pop_back(); // Roll back global history globalHistory_ >>= 1; diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index c546157021..6e315babcd 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -82,15 +82,20 @@ TEST_F(GenericPredictorTest, RAS) { // correctly, when no address aliasing has occurred TEST_F(GenericPredictorTest, Hit) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 5, " "Saturating-Count-Bits: 2, Global-History-Length: 1, RAS-entries: 5, " "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); - predictor.update(0, false, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); @@ -101,60 +106,80 @@ TEST_F(GenericPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(GenericPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 5, " "Saturating-Count-Bits: 2, Global-History-Length: 5, RAS-entries: 5, " "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); - EXPECT_EQ(prediction.target, 0x23); + EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); - EXPECT_EQ(prediction.target, 0x23); + EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } // Test Flush of RAS functionality diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index b276b3795f..7ceb8a8bc6 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -72,14 +72,19 @@ TEST_F(PerceptronPredictorTest, RAS) { // branch correctly, when no address aliasing has occurred TEST_F(PerceptronPredictorTest, Hit) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 5, " "Global-History-Length: 1, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional); - predictor.update(0, false, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); @@ -90,59 +95,79 @@ TEST_F(PerceptronPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(PerceptronPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 11, " + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 5, " "Global-History-Length: 5, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x1F, false, 0xAB, BranchType::Conditional); + predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0); + predictor.update(0, true, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); - EXPECT_EQ(prediction.target, 0x23); + EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x1F, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.update(0, false, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, true, 4, BranchType::Unconditional); - predictor.update(0, false, 4, BranchType::Unconditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.predict(0, BranchType::Conditional, 0); + predictor.update(0, false, 4, BranchType::Conditional); // Get prediction - prediction = predictor.predict(0x1F, BranchType::Conditional, 0); + prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x1F, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } // Test Flush of RAS functionality diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index 1c6664e384..c324f60a9a 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -135,12 +135,6 @@ TEST_F(PipelineExecuteUnitTest, ExecuteBranch) { uop->setBranchResults(taken, pc); })); - // Check that the branch predictor was updated with the results - EXPECT_CALL(*uop, getBranchType()).Times(1); - EXPECT_CALL(predictor, - update(insnAddress, taken, pc, BranchType::Unconditional)) - .Times(1); - // Check that empty forwarding call is made EXPECT_CALL(executionHandlers, forwardOperands(IsEmpty(), IsEmpty())) .Times(1); @@ -288,13 +282,6 @@ TEST_F(PipelineExecuteUnitTest, mispredictedBranch) { uop->setBranchResults(taken, pc); })); - // Check that the branch predictor was updated with the results - EXPECT_CALL(*uop, getBranchType()).Times(1); - - EXPECT_CALL(predictor, - update(insnAddress, taken, pc, BranchType::Conditional)) - .Times(1); - // Check that empty forwarding call is made EXPECT_CALL(executionHandlers, forwardOperands(IsEmpty(), IsEmpty())) .Times(1); diff --git a/test/unit/pipeline/RenameUnitTest.cc b/test/unit/pipeline/RenameUnitTest.cc index 6b1dc640c5..3f3013adf6 100644 --- a/test/unit/pipeline/RenameUnitTest.cc +++ b/test/unit/pipeline/RenameUnitTest.cc @@ -427,7 +427,7 @@ TEST_F(RenameUnitTest, serializedDest) { EXPECT_CALL(*uop2, getDestinationRegisters()).Times(1); EXPECT_CALL(*uop2, isLoad()).WillOnce(Return(false)); EXPECT_CALL(*uop2, isStoreAddress()).WillOnce(Return(false)); - EXPECT_CALL(*uop2, isBranch()).WillOnce(Return(false)); + EXPECT_CALL(*uop2, isBranch()).Times(2).WillRepeatedly(Return(false)); rob.commit(1); EXPECT_EQ(rob.size(), 0); diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index abc33d871a..0a5429bba1 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -365,26 +365,26 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Fourth pass through ROB -- seen count = 3; exceeds detection theshold, // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -397,26 +397,26 @@ TEST_F(ReorderBufferTest, branch) { // Re-do loop detecition // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Fourth pass through ROB -- seen count = 3; exceeds detection theshold, // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); - EXPECT_CALL(*uop, isBranch()).Times(1); + EXPECT_CALL(*uop, isBranch()).Times(2); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); } From 131517f98c9dc32077c34c2d00066529776a9b1b Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:55:05 +0000 Subject: [PATCH 096/191] Fixing unit test failures resulting from changes to BP structure --- src/include/simeng/BranchPredictor.hh | 2 +- src/include/simeng/GenericPredictor.hh | 2 +- src/include/simeng/PerceptronPredictor.hh | 4 +- src/lib/GenericPredictor.cc | 11 +-- src/lib/PerceptronPredictor.cc | 9 ++- src/lib/pipeline/FetchUnit.cc | 3 +- test/unit/GenericPredictorTest.cc | 84 +++++++++++++++++------ test/unit/MockBranchPredictor.hh | 2 +- test/unit/PerceptronPredictorTest.cc | 84 +++++++++++++++++------ 9 files changed, 145 insertions(+), 56 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 145f709f0f..4446f46bf5 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -61,7 +61,7 @@ class BranchPredictor { */ virtual void flush(uint64_t address) = 0; - virtual void addToFTQ(uint64_t address) = 0; + virtual void addToFTQ(uint64_t address, bool taken) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 697e1dc5b1..f4774cda08 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,7 +40,7 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - void addToFTQ(uint64_t address) override; + void addToFTQ(uint64_t address, bool taken) override; private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 42dd697ad6..e256c19bcf 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,7 +43,7 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - void addToFTQ(uint64_t address) override; + void addToFTQ(uint64_t address, bool taken) override; private: /** Returns the dot product of a perceptron and a history vector. Used to @@ -72,6 +72,8 @@ class PerceptronPredictor : public BranchPredictor { /** The number of previous branch directions recorded globally. */ uint64_t globalHistoryLength_; + uint64_t globalHistoryMask_; + /** The magnitude of the dot product of the perceptron and the global history, * below which the perceptron's weight must be updated */ uint64_t trainingThreshold_; diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 0d3439cab3..8b2f4b2035 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -37,7 +37,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { // Get index via an XOR hash between the global history and the lower btbBits_ // bits of the instruction address - uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; + uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); // Store the hashed index for correct hashing in update() FTQ_.emplace_back(address, hashedIndex); @@ -104,7 +104,7 @@ void GenericPredictor::update(uint64_t address, bool taken, if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << FTQ_.size()); + globalHistory_ ^= (1 << (FTQ_.size() - 1)); } } @@ -137,9 +137,12 @@ void GenericPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void GenericPredictor::addToFTQ(uint64_t address) { - uint64_t hashedIndex = (address & ((1 << btbBits_) - 1)) ^ globalHistory_; +void GenericPredictor::addToFTQ(uint64_t address, bool taken) { + // Make the hashed index and add it to the FTQ + uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); FTQ_.emplace_back(address, hashedIndex); + // Speculatively update the global history + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 38d2c9ac4b..e9b43a0630 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -20,6 +20,8 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Set up training threshold according to empirically determined formula trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); + + globalHistoryMask_ = (globalHistoryLength_ * 2) - 1; } PerceptronPredictor::~PerceptronPredictor() { @@ -82,7 +84,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // speculatively update global history globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & - ((1 << (globalHistoryLength_ * 2)) - 1); + globalHistoryMask_; return prediction; } @@ -133,7 +135,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (directionPrediction != taken) globalHistory_ ^= (1 << FTQ_.size()); + if (directionPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size() - 1)); } void PerceptronPredictor::flush(uint64_t address) { @@ -166,9 +168,10 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void PerceptronPredictor::addToFTQ(uint64_t address) { +void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction FTQ_.emplace_back(address, globalHistory_); + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } int64_t PerceptronPredictor::getDotProduct( diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 3887b49dc8..e989caacbc 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -55,7 +55,8 @@ void FetchUnit::tick() { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Let the branch predictor know the prediction is being reused so that // the FTQ can be kept up to date - branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress()); + branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchPrediction().taken); } // Cycle queue by moving front entry to back diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 6e315babcd..0f85658e52 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -106,20 +106,30 @@ TEST_F(GenericPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(GenericPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 5, " - "Saturating-Count-Bits: 2, Global-History-Length: 5, RAS-entries: 5, " + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 10, " + "Saturating-Count-Bits: 2, Global-History-Length: 10, RAS-entries: 5, " "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -129,16 +139,26 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.taken); @@ -147,15 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -165,16 +195,26 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 16, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.taken); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 6e8fb36aaa..a6db5caceb 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -13,7 +13,7 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type)); MOCK_METHOD1(flush, void(uint64_t address)); - MOCK_METHOD1(addToFTQ, void(uint64_t address)); + MOCK_METHOD2(addToFTQ, void(uint64_t address, bool taken)); }; } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 7ceb8a8bc6..ff05f51701 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -95,19 +95,29 @@ TEST_F(PerceptronPredictorTest, Hit) { // behaviours of the same branch but in different states of the program TEST_F(PerceptronPredictorTest, GlobalIndexing) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 5, " - "Global-History-Length: 5, RAS-entries: 5}}"); + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 10, " + "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -117,15 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -135,15 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -153,15 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, false, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); From 0a026f85a79a2ea4df64917b0a0df0ccf9f8f861 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:53:27 +0000 Subject: [PATCH 097/191] Getting rid of redundant info in the FTQ --- src/include/simeng/GenericPredictor.hh | 2 +- src/include/simeng/PerceptronPredictor.hh | 2 +- src/lib/GenericPredictor.cc | 9 +++------ src/lib/PerceptronPredictor.cc | 9 +++------ 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index f4774cda08..c46c35e851 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -51,7 +51,7 @@ class GenericPredictor : public BranchPredictor { std::vector> btb_; /** The previous BTB index calculated for an address. */ - std::deque> FTQ_; + std::deque FTQ_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index e256c19bcf..bb7026f15f 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -63,7 +63,7 @@ class PerceptronPredictor : public BranchPredictor { /** Fetch Target Queue containing the address and previous global history * state of branches that are currently unresolved */ - std::deque> FTQ_; + std::deque FTQ_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 8b2f4b2035..dc59765dab 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -40,7 +40,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); // Store the hashed index for correct hashing in update() - FTQ_.emplace_back(address, hashedIndex); + FTQ_.emplace_back(hashedIndex); // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); @@ -82,11 +82,8 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Sanity check to avoid segfault/wrong branch update - if (FTQ_.empty() || FTQ_.front().first != address) return; - // Get previous index calculated from the FTQ - uint64_t hashedIndex = FTQ_.front().second; + uint64_t hashedIndex = FTQ_.front(); FTQ_.pop_front(); // Calculate 2-bit saturating counter value @@ -140,7 +137,7 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - FTQ_.emplace_back(address, hashedIndex); + FTQ_.emplace_back(hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index e9b43a0630..aba19704ff 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -41,7 +41,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - FTQ_.emplace_back(address, globalHistory_); + FTQ_.emplace_back(globalHistory_); // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -91,11 +91,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Sanity check to avoid segfault/wrong branch update - //if (FTQ_.empty() || FTQ_.front().first != address) return; - // Get previous branch state from FTQ - uint64_t prevGlobalHistory = FTQ_.front().second; + uint64_t prevGlobalHistory = FTQ_.front(); FTQ_.pop_front(); // Work out hashed index @@ -170,7 +167,7 @@ void PerceptronPredictor::flush(uint64_t address) { void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction - FTQ_.emplace_back(address, globalHistory_); + FTQ_.emplace_back(globalHistory_); globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } From ec51af0341c8575d5cd3510efb674b247bdb595c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:59:35 +0000 Subject: [PATCH 098/191] Clang Format --- src/lib/PerceptronPredictor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index aba19704ff..035c2edc61 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -83,8 +83,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } // speculatively update global history - globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & - globalHistoryMask_; + globalHistory_ = + ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; return prediction; } From e73a153678b642665f1563fed798e374d48d1bc6 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:44:31 +0000 Subject: [PATCH 099/191] Adding new test for speculative global history updates --- src/include/simeng/GenericPredictor.hh | 5 ++- src/include/simeng/PerceptronPredictor.hh | 6 +-- src/lib/GenericPredictor.cc | 19 ++++----- src/lib/PerceptronPredictor.cc | 19 ++++----- test/unit/GenericPredictorTest.cc | 48 +++++++++++++++++++++++ test/unit/PerceptronPredictorTest.cc | 47 ++++++++++++++++++++++ 6 files changed, 121 insertions(+), 23 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index c46c35e851..f0d587cc37 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -50,8 +50,9 @@ class GenericPredictor : public BranchPredictor { * counter and a branch target. */ std::vector> btb_; - /** The previous BTB index calculated for an address. */ - std::deque FTQ_; + /** Fetch Target Queue containing the direction prediction and previous global + * history state of branches that are currently unresolved */ + std::deque> FTQ_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index bb7026f15f..1734d1aee7 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -61,9 +61,9 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** Fetch Target Queue containing the address and previous global history - * state of branches that are currently unresolved */ - std::deque FTQ_; + /** Fetch Target Queue containing the direction prediction and previous global + * history state of branches that are currently unresolved */ + std::deque> FTQ_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index dc59765dab..273afeb92f 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -39,9 +39,6 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // bits of the instruction address uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - // Store the hashed index for correct hashing in update() - FTQ_.emplace_back(hashedIndex); - // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = @@ -73,6 +70,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, if (!prediction.taken) prediction.target = address + 4; } + // Store the hashed index for correct hashing in update() + FTQ_.emplace_back(prediction.taken, hashedIndex); + // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; @@ -82,8 +82,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Get previous index calculated from the FTQ - uint64_t hashedIndex = FTQ_.front(); + // Get previous prediciton and index calculated from the FTQ + bool prevPrediction = FTQ_.front().first; + uint64_t hashedIndex = FTQ_.front().second; FTQ_.pop_front(); // Calculate 2-bit saturating counter value @@ -98,10 +99,10 @@ void GenericPredictor::update(uint64_t address, bool taken, btb_[hashedIndex] = {satCntVal, targetAddress}; // Update global history if prediction was incorrect - if (btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)) != taken) { + if (prevPrediction != taken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << (FTQ_.size() - 1)); + globalHistory_ ^= (1 << (FTQ_.size())); } } @@ -128,7 +129,7 @@ void GenericPredictor::flush(uint64_t address) { } // If possible, pop instruction from FTQ - if (!FTQ_.empty()) FTQ_.pop_back(); + FTQ_.pop_back(); // Roll back global history globalHistory_ >>= 1; @@ -137,7 +138,7 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - FTQ_.emplace_back(hashedIndex); + FTQ_.emplace_back(taken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 035c2edc61..9d1142fc7b 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -38,11 +38,6 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - // Store the global history for correct hashing in update() -- - // needs to be global history and not the hashed index as hashing loses - // information at longer global history lengths - FTQ_.emplace_back(globalHistory_); - // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -82,6 +77,11 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, if (!prediction.taken) prediction.target = address + 4; } + // Store the global history for correct hashing in update() -- + // needs to be global history and not the hashed index as hashing loses + // information at longer global history lengths + FTQ_.emplace_back(prediction.taken, globalHistory_); + // speculatively update global history globalHistory_ = ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; @@ -91,8 +91,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Get previous branch state from FTQ - uint64_t prevGlobalHistory = FTQ_.front(); + // Get previous branch state and prediction from FTQ + bool prevPrediction = FTQ_.front().first; + uint64_t prevGlobalHistory = FTQ_.front().second; FTQ_.pop_front(); // Work out hashed index @@ -132,7 +133,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (directionPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size() - 1)); + if (prevPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -167,7 +168,7 @@ void PerceptronPredictor::flush(uint64_t address) { void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction - FTQ_.emplace_back(globalHistory_); + FTQ_.emplace_back(taken, globalHistory_); globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 0f85658e52..9fb10ba168 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -260,4 +260,52 @@ TEST_F(GenericPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } +// Test that update correctly corrects the speculatively updated gloabl history +TEST_F(GenericPredictorTest, speculativeGlobalHistory) { + simeng::config::SimInfo::addToConfig( + "{Branch-Predictor: {BTB-Tag-Bits: 2, Saturating-Count-Bits: 6, " + "Global-History-Length: 6, RAS-entries: 10, Fallback-Static-Predictor: " + "Always-Taken}}"); + auto predictor = simeng::GenericPredictor(); + // spool up a global history to set the target address + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure default behaviour for first encounter + auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0x4); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + + // recreate this global history but with incorrect predictions + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure default behaviour for first encounter + prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0xAB); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); +} + } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index ff05f51701..70485355dd 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -247,4 +247,51 @@ TEST_F(PerceptronPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } +// Test that update correctly corrects the speculatively updated gloabl history +TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { + simeng::config::SimInfo::addToConfig( + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 2, " + "Global-History-Length: 6, RAS-entries: 5}}"); + auto predictor = simeng::PerceptronPredictor(); + // spool up a global history to set the target address + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, true); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure default behaviour for first encounter + auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0x4); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + + // recreate this global history but with incorrect predictions + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + predictor.addToFTQ(0, false); + predictor.update(0, true, 4, BranchType::Conditional); + // Ensure prediction is correct with new target address + prediction = predictor.predict(0xFF, BranchType::Conditional, 0); + EXPECT_TRUE(prediction.taken); + EXPECT_EQ(prediction.target, 0xAB); + // Set entry in BTB + predictor.update(0xFF, true, 0xAB, BranchType::Conditional); +} + } // namespace simeng From b611a83b9b015d56137e2eb2d8f27aaeb826b766 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:52:45 +0000 Subject: [PATCH 100/191] Addressing superficial comments on PR --- src/include/simeng/BranchPredictor.hh | 1 + src/include/simeng/GenericPredictor.hh | 3 ++- src/include/simeng/PerceptronPredictor.hh | 5 ++++- src/lib/GenericPredictor.cc | 22 +++++++++++----------- src/lib/PerceptronPredictor.cc | 18 ++++++++---------- src/lib/pipeline/ReorderBuffer.cc | 2 +- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 4446f46bf5..39d2c2f2d5 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -61,6 +61,7 @@ class BranchPredictor { */ virtual void flush(uint64_t address) = 0; + /** Adds instruction to the Fetch Target Queue without making a new prediction */ virtual void addToFTQ(uint64_t address, bool taken) = 0; }; diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index f0d587cc37..009a6fbd3b 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,6 +40,7 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + /** Adds instruction to the Fetch Target Queue without making a new prediction */ void addToFTQ(uint64_t address, bool taken) override; private: @@ -52,7 +53,7 @@ class GenericPredictor : public BranchPredictor { /** Fetch Target Queue containing the direction prediction and previous global * history state of branches that are currently unresolved */ - std::deque> FTQ_; + std::deque> ftq_; /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 1734d1aee7..29cf3eb460 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,6 +43,7 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; + /** Adds instruction to the Fetch Target Queue without making a new prediction */ void addToFTQ(uint64_t address, bool taken) override; private: @@ -63,7 +64,7 @@ class PerceptronPredictor : public BranchPredictor { /** Fetch Target Queue containing the direction prediction and previous global * history state of branches that are currently unresolved */ - std::deque> FTQ_; + std::deque> ftq_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. */ @@ -72,6 +73,8 @@ class PerceptronPredictor : public BranchPredictor { /** The number of previous branch directions recorded globally. */ uint64_t globalHistoryLength_; + /** A bit mask for truncating the global history to the correct size. + * Stored as a member variable to avoid duplicative calculation */ uint64_t globalHistoryMask_; /** The magnitude of the dot product of the perceptron and the global history, diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 273afeb92f..a7d154d49e 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -30,14 +30,14 @@ GenericPredictor::~GenericPredictor() { btb_.clear(); ras_.clear(); rasHistory_.clear(); - FTQ_.clear(); + ftq_.clear(); } BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { - // Get index via an XOR hash between the global history and the lower btbBits_ - // bits of the instruction address - uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); + // Get index via an XOR hash between the global history and the instruction address. + // This hash is then ANDed to keep it within bounds of the btb + uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); @@ -71,7 +71,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, } // Store the hashed index for correct hashing in update() - FTQ_.emplace_back(prediction.taken, hashedIndex); + ftq_.emplace_back(prediction.taken, hashedIndex); // Speculatively update the global history globalHistory_ = @@ -83,9 +83,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { // Get previous prediciton and index calculated from the FTQ - bool prevPrediction = FTQ_.front().first; - uint64_t hashedIndex = FTQ_.front().second; - FTQ_.pop_front(); + bool prevPrediction = ftq_.front().first; + uint64_t hashedIndex = ftq_.front().second; + ftq_.pop_front(); // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; @@ -102,7 +102,7 @@ void GenericPredictor::update(uint64_t address, bool taken, if (prevPrediction != taken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << (FTQ_.size())); + globalHistory_ ^= (1 << (ftq_.size())); } } @@ -129,7 +129,7 @@ void GenericPredictor::flush(uint64_t address) { } // If possible, pop instruction from FTQ - FTQ_.pop_back(); + ftq_.pop_back(); // Roll back global history globalHistory_ >>= 1; @@ -138,7 +138,7 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); - FTQ_.emplace_back(taken, hashedIndex); + ftq_.emplace_back(taken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; } diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 9d1142fc7b..6b1be4d407 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -27,7 +27,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) PerceptronPredictor::~PerceptronPredictor() { ras_.clear(); rasHistory_.clear(); - FTQ_.clear(); + ftq_.clear(); } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, @@ -80,7 +80,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - FTQ_.emplace_back(prediction.taken, globalHistory_); + ftq_.emplace_back(prediction.taken, globalHistory_); // speculatively update global history globalHistory_ = @@ -92,9 +92,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { // Get previous branch state and prediction from FTQ - bool prevPrediction = FTQ_.front().first; - uint64_t prevGlobalHistory = FTQ_.front().second; - FTQ_.pop_front(); + bool prevPrediction = ftq_.front().first; + uint64_t prevGlobalHistory = ftq_.front().second; + ftq_.pop_front(); // Work out hashed index uint64_t hashedIndex = @@ -133,7 +133,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (prevPrediction != taken) globalHistory_ ^= (1 << (FTQ_.size())); + if (prevPrediction != taken) globalHistory_ ^= (1 << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -158,9 +158,7 @@ void PerceptronPredictor::flush(uint64_t address) { rasHistory_.erase(it); } - // If possible, pop instruction from FTQ - // if (!FTQ_.empty()) FTQ_.pop_back(); - FTQ_.pop_back(); + ftq_.pop_back(); // Roll back global history globalHistory_ >>= 1; @@ -168,7 +166,7 @@ void PerceptronPredictor::flush(uint64_t address) { void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { // Add instruction to the FTQ in event of reused prediction - FTQ_.emplace_back(taken, globalHistory_); + ftq_.emplace_back(taken, globalHistory_); globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 4c89c30e66..8ec673ace1 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -154,7 +154,7 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { } // If it is a branch, now update the predictor (here to ensure order of - // updates is correct + // updates is correct) if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); From 268a55543e3e7b6b523323be603905de495cde49 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:19:17 +0000 Subject: [PATCH 101/191] Adding EXPECT_CALL for branch predictor in reorderBufferTest.cc --- test/unit/pipeline/ReorderBufferTest.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 0a5429bba1..d0a7b9bf2f 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -366,18 +366,24 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -385,6 +391,8 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -398,18 +406,24 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -417,6 +431,8 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); + EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), + uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); } From a2d471c85730088428bb648036af4c5795d490a5 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:55:52 +0000 Subject: [PATCH 102/191] Moving branch statistic collectiong to Reorder buffer and updating tests accordingly --- src/include/simeng/pipeline/ExecuteUnit.hh | 12 ------------ src/include/simeng/pipeline/ReorderBuffer.hh | 12 ++++++++++++ src/lib/models/inorder/Core.cc | 19 ++++++++++--------- src/lib/models/outoforder/Core.cc | 9 ++------- src/lib/pipeline/ExecuteUnit.cc | 11 ----------- src/lib/pipeline/ReorderBuffer.cc | 11 +++++++++++ test/unit/pipeline/ExecuteUnitTest.cc | 4 ---- test/unit/pipeline/ReorderBufferTest.cc | 5 +++++ 8 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index a72de10850..c803476873 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -55,12 +55,6 @@ class ExecuteUnit { * stall, if applicable. */ void purgeFlushed(); - /** Retrieve the number of branch instructions that have been executed. */ - uint64_t getBranchExecutedCount() const; - - /** Retrieve the number of branch mispredictions. */ - uint64_t getBranchMispredictedCount() const; - /** Retrieve the number of active execution cycles. */ uint64_t getCycles() const; @@ -124,12 +118,6 @@ class ExecuteUnit { /** The cycle this unit will become unstalled. */ uint64_t stallUntil_ = 0; - /** The number of branch instructions that were executed. */ - uint64_t branchesExecuted_ = 0; - - /** The number of branch mispredictions that were observed. */ - uint64_t branchMispredicts_ = 0; - /** The number of active execution cycles that were observed. */ uint64_t cycles_ = 0; }; diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index 278a0174ca..abe4a94b34 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -85,6 +85,12 @@ class ReorderBuffer { /** Get the number of speculated loads which violated load-store ordering. */ uint64_t getViolatingLoadsCount() const; + /** Retrieve the number of branch instructions that have been executed. */ + uint64_t getBranchExecutedCount() const; + + /** Retrieve the number of branch mispredictions. */ + uint64_t getBranchMispredictedCount() const; + private: /** A reference to the register alias table. */ RegisterAliasTable& rat_; @@ -144,6 +150,12 @@ class ReorderBuffer { /** The number of speculative loads which violated load-store ordering. */ uint64_t loadViolations_ = 0; + + /** The number of branch instructions that were executed. */ + uint64_t branchesExecuted_ = 0; + + /** The number of branch mispredictions that were observed. */ + uint64_t branchMispredicts_ = 0; }; } // namespace pipeline diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 16b21d2a4d..09a5602977 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -148,21 +148,22 @@ std::map Core::getStats() const { ipcStr << std::setprecision(2) << ipc; // Sum up the branch stats reported across the execution units. - uint64_t totalBranchesExecuted = 0; - uint64_t totalBranchMispredicts = 0; - totalBranchesExecuted += executeUnit_.getBranchExecutedCount(); - totalBranchMispredicts += executeUnit_.getBranchMispredictedCount(); - auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesExecuted); +// uint64_t totalBranchesExecuted = 0; +// uint64_t totalBranchMispredicts = 0; +// totalBranchesExecuted += executeUnit_.getBranchExecutedCount(); +// totalBranchMispredicts += executeUnit_.getBranchMispredictedCount(); +// auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / +// static_cast(totalBranchesExecuted); std::ostringstream branchMissRateStr; - branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; +// branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; + branchMissRateStr << "Not yet implemented for in order"; return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, {"flushes", std::to_string(flushes_)}, - {"branch.executed", std::to_string(totalBranchesExecuted)}, - {"branch.mispredict", std::to_string(totalBranchMispredicts)}, +// {"branch.executed", std::to_string(totalBranchesExecuted)}, +// {"branch.mispredict", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}}; } diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index f853e9efd3..0d39a8b936 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,14 +224,9 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = 0; - uint64_t totalBranchMispredicts = 0; + uint64_t totalBranchesExecuted = reorderBuffer_.getBranchExecutedCount(); + uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); - // Sum up the branch stats reported across the execution units. - for (auto& eu : executionUnits_) { - totalBranchesExecuted += eu.getBranchExecutedCount(); - totalBranchMispredicts += eu.getBranchMispredictedCount(); - } auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / static_cast(totalBranchesExecuted); std::ostringstream branchMissRateStr; diff --git a/src/lib/pipeline/ExecuteUnit.cc b/src/lib/pipeline/ExecuteUnit.cc index b1b7d5fed7..28a04dde28 100644 --- a/src/lib/pipeline/ExecuteUnit.cc +++ b/src/lib/pipeline/ExecuteUnit.cc @@ -138,15 +138,11 @@ void ExecuteUnit::execute(std::shared_ptr& uop) { if (uop->isBranch()) { pc_ = uop->getBranchAddress(); - // Update the branch instruction counter - branchesExecuted_++; if (uop->wasBranchMispredicted()) { // Misprediction; flush the pipeline shouldFlush_ = true; flushAfter_ = uop->getInstructionId(); - // Update the branch misprediction counter - branchMispredicts_++; } } @@ -208,13 +204,6 @@ void ExecuteUnit::purgeFlushed() { } } -uint64_t ExecuteUnit::getBranchExecutedCount() const { - return branchesExecuted_; -} -uint64_t ExecuteUnit::getBranchMispredictedCount() const { - return branchMispredicts_; -} - uint64_t ExecuteUnit::getCycles() const { return cycles_; } bool ExecuteUnit::isEmpty() const { diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 8ec673ace1..2b15fcd414 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -158,6 +158,10 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); + // Update the branch instruction counter + branchesExecuted_++; + // Update the branch misprediction counter + if (uop->wasBranchMispredicted()) branchMispredicts_++; } buffer_.pop_front(); @@ -214,5 +218,12 @@ uint64_t ReorderBuffer::getViolatingLoadsCount() const { return loadViolations_; } +uint64_t ReorderBuffer::getBranchExecutedCount() const { + return branchesExecuted_; +} +uint64_t ReorderBuffer::getBranchMispredictedCount() const { + return branchMispredicts_; +} + } // namespace pipeline } // namespace simeng diff --git a/test/unit/pipeline/ExecuteUnitTest.cc b/test/unit/pipeline/ExecuteUnitTest.cc index c324f60a9a..3665628b8c 100644 --- a/test/unit/pipeline/ExecuteUnitTest.cc +++ b/test/unit/pipeline/ExecuteUnitTest.cc @@ -146,8 +146,6 @@ TEST_F(PipelineExecuteUnitTest, ExecuteBranch) { EXPECT_EQ(executeUnit.shouldFlush(), false); EXPECT_EQ(output.getTailSlots()[0].get(), uop); - EXPECT_EQ(executeUnit.getBranchExecutedCount(), 1); - EXPECT_EQ(executeUnit.getBranchMispredictedCount(), 0); } // Test that an instruction that already encountered an exception will raise it @@ -293,8 +291,6 @@ TEST_F(PipelineExecuteUnitTest, mispredictedBranch) { EXPECT_EQ(executeUnit.shouldFlush(), true); EXPECT_EQ(output.getTailSlots()[0].get(), uop); - EXPECT_EQ(executeUnit.getBranchExecutedCount(), 1); - EXPECT_EQ(executeUnit.getBranchMispredictedCount(), 1); EXPECT_EQ(executeUnit.getFlushAddress(), pc); EXPECT_EQ(executeUnit.getFlushInsnId(), insnID); } diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index d0a7b9bf2f..be9c4086a7 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -361,6 +361,7 @@ TEST_F(ReorderBufferTest, branch) { uopPtr->setInstructionId(0); uopPtr->setInstructionAddress(insnAddr); uopPtr->setBranchPrediction(pred); + uop->setExecuted(true); uopPtr->setCommitReady(); // First pass through ROB -- seen count reset to 0 as new branch @@ -435,6 +436,10 @@ TEST_F(ReorderBufferTest, branch) { uop->getBranchAddress(), uop->getBranchType())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); + + // Check that branch metrics have been correctly collected + EXPECT_EQ(reorderBuffer.getBranchExecutedCount(), 8); + EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); } // Tests that only those destination registers which have been renamed are From fcfc467ad9cc6285d4bb2bd709f7d06be6482ba5 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:12:10 +0000 Subject: [PATCH 103/191] Removing BP stats from in-order core getstats --- src/lib/models/inorder/Core.cc | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 09a5602977..373529e695 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -147,24 +147,10 @@ std::map Core::getStats() const { std::ostringstream ipcStr; ipcStr << std::setprecision(2) << ipc; - // Sum up the branch stats reported across the execution units. -// uint64_t totalBranchesExecuted = 0; -// uint64_t totalBranchMispredicts = 0; -// totalBranchesExecuted += executeUnit_.getBranchExecutedCount(); -// totalBranchMispredicts += executeUnit_.getBranchMispredictedCount(); -// auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / -// static_cast(totalBranchesExecuted); - std::ostringstream branchMissRateStr; -// branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; - branchMissRateStr << "Not yet implemented for in order"; - return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, - {"flushes", std::to_string(flushes_)}, -// {"branch.executed", std::to_string(totalBranchesExecuted)}, -// {"branch.mispredict", std::to_string(totalBranchMispredicts)}, - {"branch.missrate", branchMissRateStr.str()}}; + {"flushes", std::to_string(flushes_)}; } void Core::raiseException(const std::shared_ptr& instruction) { From 8391bc94cf05cce02dbb22e414fdbf929da7a9e8 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:20:21 +0000 Subject: [PATCH 104/191] Moving branch prediction stat collection to fetch unit to better align with branch metrics reported by PMU events in A64FX --- src/include/simeng/pipeline/FetchUnit.hh | 6 ++++++ src/include/simeng/pipeline/ReorderBuffer.hh | 6 ------ src/lib/models/inorder/Core.cc | 2 +- src/lib/models/outoforder/Core.cc | 2 +- src/lib/pipeline/FetchUnit.cc | 6 ++++++ src/lib/pipeline/ReorderBuffer.cc | 6 ------ test/unit/pipeline/ReorderBufferTest.cc | 3 +-- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index 09e8bb31f6..0b16316888 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -69,6 +69,9 @@ class FetchUnit { /** Clear the loop buffer. */ void flushLoopBuffer(); + /** Retrieve the number of branch instructions that have been executed. */ + uint64_t getBranchExecutedCount() const; + private: /** An output buffer connecting this unit to the decode unit. */ PipelineBuffer& output_; @@ -118,6 +121,9 @@ class FetchUnit { /** The amount of data currently in the fetch buffer. */ uint16_t bufferedBytes_ = 0; + /** The number of branch instructions that were executed. */ + uint64_t branchesExecuted_ = 0; + /** Let the following PipelineFetchUnitTest derived classes be a friend of * this class to allow proper testing of 'tick' function. */ friend class PipelineFetchUnitTest_invalidMinBytesAtEndOfBuffer_Test; diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index abe4a94b34..64a32ce78b 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -85,9 +85,6 @@ class ReorderBuffer { /** Get the number of speculated loads which violated load-store ordering. */ uint64_t getViolatingLoadsCount() const; - /** Retrieve the number of branch instructions that have been executed. */ - uint64_t getBranchExecutedCount() const; - /** Retrieve the number of branch mispredictions. */ uint64_t getBranchMispredictedCount() const; @@ -151,9 +148,6 @@ class ReorderBuffer { /** The number of speculative loads which violated load-store ordering. */ uint64_t loadViolations_ = 0; - /** The number of branch instructions that were executed. */ - uint64_t branchesExecuted_ = 0; - /** The number of branch mispredictions that were observed. */ uint64_t branchMispredicts_ = 0; }; diff --git a/src/lib/models/inorder/Core.cc b/src/lib/models/inorder/Core.cc index 373529e695..add307f714 100644 --- a/src/lib/models/inorder/Core.cc +++ b/src/lib/models/inorder/Core.cc @@ -150,7 +150,7 @@ std::map Core::getStats() const { return {{"cycles", std::to_string(ticks_)}, {"retired", std::to_string(retired)}, {"ipc", ipcStr.str()}, - {"flushes", std::to_string(flushes_)}; + {"flushes", std::to_string(flushes_)}}; } void Core::raiseException(const std::shared_ptr& instruction) { diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 0d39a8b936..a3bc30dc46 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,7 +224,7 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = reorderBuffer_.getBranchExecutedCount(); + uint64_t totalBranchesExecuted = fetchUnit_.getBranchExecutedCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index e989caacbc..28427a0911 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -57,6 +57,7 @@ void FetchUnit::tick() { // the FTQ can be kept up to date branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchPrediction().taken); + branchesExecuted_++; } // Cycle queue by moving front entry to back @@ -151,6 +152,7 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { prediction = branchPredictor_.predict(pc_, macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); + branchesExecuted_++; macroOp[0]->setBranchPrediction(prediction); } @@ -284,5 +286,9 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } +uint64_t FetchUnit::getBranchExecutedCount() const { + return branchesExecuted_; +} + } // namespace pipeline } // namespace simeng diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 2b15fcd414..47b231e866 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -158,8 +158,6 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType()); - // Update the branch instruction counter - branchesExecuted_++; // Update the branch misprediction counter if (uop->wasBranchMispredicted()) branchMispredicts_++; } @@ -217,10 +215,6 @@ uint64_t ReorderBuffer::getInstructionsCommittedCount() const { uint64_t ReorderBuffer::getViolatingLoadsCount() const { return loadViolations_; } - -uint64_t ReorderBuffer::getBranchExecutedCount() const { - return branchesExecuted_; -} uint64_t ReorderBuffer::getBranchMispredictedCount() const { return branchMispredicts_; } diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index be9c4086a7..23960d058a 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -437,8 +437,7 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); - // Check that branch metrics have been correctly collected - EXPECT_EQ(reorderBuffer.getBranchExecutedCount(), 8); + // Check that branch misprediction metrics have been correctly collected EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); } From b31fa8bff1a4f72f29349b67aea9065858cd3d03 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:20:50 +0000 Subject: [PATCH 105/191] Fixing typo --- test/unit/pipeline/ReorderBufferTest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 23960d058a..aa59fe0448 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -428,7 +428,7 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); - // Fourth pass through ROB -- seen count = 3; exceeds detection theshold, + // Fourth pass through ROB -- seen count = 3; exceeds detection threshold, // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); From 18933f8649cab56be5d9bf88053af754476d07e7 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:48:32 +0000 Subject: [PATCH 106/191] Clang format --- src/include/simeng/BranchPredictor.hh | 3 ++- src/include/simeng/GenericPredictor.hh | 3 ++- src/include/simeng/PerceptronPredictor.hh | 3 ++- src/lib/GenericPredictor.cc | 7 ++++--- src/lib/pipeline/DecodeUnit.cc | 3 ++- src/lib/pipeline/FetchUnit.cc | 4 +--- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 39d2c2f2d5..eac6e5aaa0 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -61,7 +61,8 @@ class BranchPredictor { */ virtual void flush(uint64_t address) = 0; - /** Adds instruction to the Fetch Target Queue without making a new prediction */ + /** Adds instruction to the Fetch Target Queue without making a new prediction + */ virtual void addToFTQ(uint64_t address, bool taken) = 0; }; diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 009a6fbd3b..cb34e30ef5 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -40,7 +40,8 @@ class GenericPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction */ + /** Adds instruction to the Fetch Target Queue without making a new prediction + */ void addToFTQ(uint64_t address, bool taken) override; private: diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 29cf3eb460..9fd040fa8e 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -43,7 +43,8 @@ class PerceptronPredictor : public BranchPredictor { /** Provides RAS rewinding behaviour. */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction */ + /** Adds instruction to the Fetch Target Queue without making a new prediction + */ void addToFTQ(uint64_t address, bool taken) override; private: diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index a7d154d49e..ad28c13378 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -35,9 +35,10 @@ GenericPredictor::~GenericPredictor() { BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { - // Get index via an XOR hash between the global history and the instruction address. - // This hash is then ANDed to keep it within bounds of the btb - uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + // Get index via an XOR hash between the global history and the instruction + // address. This hash is then ANDed to keep it within bounds of the btb + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 647f24ec21..4c557bfd56 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -95,7 +95,8 @@ uint64_t DecodeUnit::getEarlyFlushes() const { return earlyFlushes_; } void DecodeUnit::purgeFlushed() { while (!microOps_.empty()) { - if (microOps_.front()->isBranch()) predictor_.flush(microOps_.front()->getInstructionAddress()); + if (microOps_.front()->isBranch()) + predictor_.flush(microOps_.front()->getInstructionAddress()); microOps_.pop_front(); } } diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 28427a0911..2c753328db 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -286,9 +286,7 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } -uint64_t FetchUnit::getBranchExecutedCount() const { - return branchesExecuted_; -} +uint64_t FetchUnit::getBranchExecutedCount() const { return branchesExecuted_; } } // namespace pipeline } // namespace simeng From fa594f40b58f1d4eddff6cf7a64edbeef7d1a154 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:18:49 +0100 Subject: [PATCH 107/191] Adding ftq description in the BP docs --- docs/sphinx/developer/components/branchPred.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 6466802080..8331b0c9bc 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,6 +17,8 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottow of the queue on ``update`` and ``flush``. + Generic Predictor ----------------- From b10dcbcee36c082d07c2978a6f9714447f70b529 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:23:00 +0100 Subject: [PATCH 108/191] Attending to Generic Predictor comments --- src/lib/GenericPredictor.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index ad28c13378..d0c23737db 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -36,7 +36,9 @@ GenericPredictor::~GenericPredictor() { BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset) { // Get index via an XOR hash between the global history and the instruction - // address. This hash is then ANDed to keep it within bounds of the btb + // address. This hash is then ANDed to keep it within bounds of the btb. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in a 64 bit ISA. uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); @@ -83,7 +85,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, void GenericPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) { - // Get previous prediciton and index calculated from the FTQ + // Get previous prediction and index calculated from the FTQ bool prevPrediction = ftq_.front().first; uint64_t hashedIndex = ftq_.front().second; ftq_.pop_front(); @@ -138,7 +140,8 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool taken) { // Make the hashed index and add it to the FTQ - uint64_t hashedIndex = (address ^ globalHistory_) & ((1 << btbBits_) - 1); + uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) + - 1); ftq_.emplace_back(taken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; From c0a79cef17d2660b284669ecfabe6198262fab6e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:25:09 +0100 Subject: [PATCH 109/191] Docs typo fixed --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 8331b0c9bc..e2ff1d1ec1 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,7 +17,7 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottow of the queue on ``update`` and ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottom of the queue on ``update`` and from the top of the queue on ``flush``. Generic Predictor ----------------- From b7b55508b6542d172f57f7d7c7c76c05bb79e314 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:40:33 +0100 Subject: [PATCH 110/191] Adding buffer check comment --- src/lib/models/outoforder/Core.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index a3bc30dc46..667d89ce0c 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -259,6 +259,8 @@ void Core::raiseException(const std::shared_ptr& instruction) { } void Core::handleException() { + // Check the buffer entries to see if they are branch instructions. If so, + // flush them from the BP for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; if (!macroOp.empty() && macroOp[0]->isBranch()) { From 071c4841e3f532162aec0e3db3b8a94a88784121 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:43:05 +0100 Subject: [PATCH 111/191] Fixing typo --- test/unit/GenericPredictorTest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 9fb10ba168..2fe34f48a3 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -260,7 +260,7 @@ TEST_F(GenericPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } -// Test that update correctly corrects the speculatively updated gloabl history +// Test that update correctly corrects the speculatively updated global history TEST_F(GenericPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( "{Branch-Predictor: {BTB-Tag-Bits: 2, Saturating-Count-Bits: 6, " From cf1946542ed17593683726c1ce261cdf73329e0f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:04:22 +0100 Subject: [PATCH 112/191] Updating comment re shifting the address to get the hashed index --- src/lib/GenericPredictor.cc | 2 +- src/lib/PerceptronPredictor.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index d0c23737db..0f0d1deec9 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -38,7 +38,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these - // are always 0 in a 64 bit ISA. + // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 6b1be4d407..9acd49a4d8 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -35,6 +35,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Get the hashed index for the prediction table. XOR the global history with // the non-zero bits of the address, and then keep only the btbBits_ bits of // the output to keep it in bounds of the prediction table. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); From 9f6c6a6e5c91267f39b9c464ef43a931e785704a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:25:34 +0100 Subject: [PATCH 113/191] Adding comment re multiplying global history length by two --- src/lib/GenericPredictor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 0f0d1deec9..f9565a7687 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -23,6 +23,9 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) btb_ = std::vector>(1 << btbBits_, {satCntVal, 0}); // Alter globalHistoryLength_ value to better suit required format in update() + // Multiply original globalHistoryLength_ by two so that extra branch + // outcomes are stored to allow rolling back the speculatively updated + // global history in the event of a misprediction. globalHistoryLength_ = (1 << (globalHistoryLength_ * 2)) - 1; } From daaa2f6d3b616ca4147d7d9bd48ddf3d4d5acb88 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:29:39 +0100 Subject: [PATCH 114/191] Renaming getBranchExecutedCount to getBranchFetchedCount --- src/include/simeng/pipeline/FetchUnit.hh | 4 ++-- src/lib/models/outoforder/Core.cc | 2 +- src/lib/pipeline/FetchUnit.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index 0b16316888..c5a7383b4f 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -69,8 +69,8 @@ class FetchUnit { /** Clear the loop buffer. */ void flushLoopBuffer(); - /** Retrieve the number of branch instructions that have been executed. */ - uint64_t getBranchExecutedCount() const; + /** Retrieve the number of branch instructions that have been fetched. */ + uint64_t getBranchFetchedCount() const; private: /** An output buffer connecting this unit to the decode unit. */ diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 667d89ce0c..eb4bf41bcc 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,7 +224,7 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = fetchUnit_.getBranchExecutedCount(); + uint64_t totalBranchesExecuted = fetchUnit_.getBranchFetchedCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 2c753328db..95df50ce7b 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -286,7 +286,7 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } -uint64_t FetchUnit::getBranchExecutedCount() const { return branchesExecuted_; } +uint64_t FetchUnit::getBranchFetchedCount() const { return branchesExecuted_; } } // namespace pipeline } // namespace simeng From 284f3c8570d4c27c5fdb2d318924707be18904e8 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:56:24 +0100 Subject: [PATCH 115/191] Adding globalHistoryMask_ variable to genericPredictor --- src/include/simeng/GenericPredictor.hh | 4 ++++ src/lib/GenericPredictor.cc | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index cb34e30ef5..24013efb85 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -66,6 +66,10 @@ class GenericPredictor : public BranchPredictor { /** The number of previous branch directions recorded globally. */ uint16_t globalHistoryLength_; + /** A bit mask for truncating the global history to the correct size. + * Stored as a member variable to avoid duplicative calculation */ + uint64_t globalHistoryMask_; + /** A return address stack. */ std::deque ras_; diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index f9565a7687..06875a51c5 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -26,7 +26,7 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // Multiply original globalHistoryLength_ by two so that extra branch // outcomes are stored to allow rolling back the speculatively updated // global history in the event of a misprediction. - globalHistoryLength_ = (1 << (globalHistoryLength_ * 2)) - 1; + globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; } GenericPredictor::~GenericPredictor() { @@ -81,7 +81,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Speculatively update the global history globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & globalHistoryLength_; + ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; return prediction; } @@ -147,7 +147,7 @@ void GenericPredictor::addToFTQ(uint64_t address, bool taken) { - 1); ftq_.emplace_back(taken, hashedIndex); // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryLength_; + globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; } } // namespace simeng From e4df5c58e06d81775ccc8afbf2bb9a007e82bf63 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:03:19 +0100 Subject: [PATCH 116/191] Adding more detail to virtual flush and update functions re order of calls --- src/include/simeng/BranchPredictor.hh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index eac6e5aaa0..1b62beea98 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -52,13 +52,16 @@ class BranchPredictor { int64_t knownOffset) = 0; /** Provide branch results to update the prediction model for the specified - * instruction address. */ + * instruction address. Update must be called on instructions in program + * order */ virtual void update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type) = 0; /** Provides flushing behaviour for the implemented branch prediction schemes - * via the instruction address. - */ + * via the instruction address. Branches must be flushed in reverse + * program order (though, if a block of n instructions is being flushed at + * once, the exact order that the individual instructions within this block + * are flushed does not matter so long as they are all flushed) */ virtual void flush(uint64_t address) = 0; /** Adds instruction to the Fetch Target Queue without making a new prediction From 6313b6ae778bd93bd65bb6f0fa402657eca4b8fe Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:07:29 +0100 Subject: [PATCH 117/191] reversing order of purge flush from decodeUnit --- src/lib/pipeline/DecodeUnit.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 4c557bfd56..8748690488 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -95,9 +95,9 @@ uint64_t DecodeUnit::getEarlyFlushes() const { return earlyFlushes_; } void DecodeUnit::purgeFlushed() { while (!microOps_.empty()) { - if (microOps_.front()->isBranch()) - predictor_.flush(microOps_.front()->getInstructionAddress()); - microOps_.pop_front(); + if (microOps_.back()->isBranch()) + predictor_.flush(microOps_.back()->getInstructionAddress()); + microOps_.pop_back(); } } From 882251a7beeb916cba4734622d74e14ecb69b068 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:52:16 +0100 Subject: [PATCH 118/191] Moving buffer branch flush functionality from core.cc to PipelineBuffer.hh --- src/include/simeng/pipeline/PipelineBuffer.hh | 28 +++++++++++++++++++ src/lib/models/outoforder/Core.cc | 22 ++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index 6e128ae684..b65d21c61a 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,6 +4,8 @@ #include #include +#include "simeng/BranchPredictor.hh" + namespace simeng { namespace pipeline { @@ -73,6 +75,32 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } + void flushBranchMicroOps(BranchPredictor& branchPredictor) { + for (size_t slot = 0; slot < width; slot++) { + auto& uop = getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + branchPredictor.flush(uop->getInstructionAddress()); + } + uop = getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + branchPredictor.flush(uop->getInstructionAddress()); + } + } + } + + void flushBranchMacroOps(BranchPredictor& branchPredictor) { + for (size_t slot = 0; slot < width; slot++) { + auto& macroOp = getTailSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + branchPredictor.flush(macroOp[0]->getInstructionAddress()); + } + macroOp = getHeadSlots()[slot]; + if (!macroOp.empty() && macroOp[0]->isBranch()) { + branchPredictor.flush(macroOp[0]->getInstructionAddress()); + } + } + } + private: /** The width of each row of slots. */ uint16_t width; diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index eb4bf41bcc..2cb1b28be4 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -261,29 +261,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check the buffer entries to see if they are branch instructions. If so, // flush them from the BP - for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { - auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - } + fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { - auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - uop = decodeToRenameBuffer_.getHeadSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - } + decodeToRenameBuffer_.flushBranchMicroOps(predictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); From abcc64d9ae1845610ccc367d25115a9d842e6c43 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:39:46 +0100 Subject: [PATCH 119/191] Rebasing --- .../developer/arch/supported/aarch64.rst | 4 +- .../developer/components/branchPred.rst | 8 +-- .../developer/components/coreinstance.rst | 2 +- .../components/pipeline/components.rst | 2 +- .../developer/components/pipeline/units.rst | 10 ++-- src/include/simeng/AlwaysNotTakenPredictor.hh | 6 +- src/include/simeng/BranchPredictor.hh | 14 ++--- src/include/simeng/GenericPredictor.hh | 4 +- src/include/simeng/Instruction.hh | 6 +- src/include/simeng/PerceptronPredictor.hh | 4 +- .../arch/aarch64/helpers/conditional.hh | 4 +- src/include/simeng/config/yaml/ryml.hh | 20 +++---- src/lib/GenericPredictor.cc | 32 +++++------ src/lib/PerceptronPredictor.cc | 26 +++++---- src/lib/arch/aarch64/Instruction.cc | 4 +- src/lib/arch/riscv/Instruction.cc | 4 +- src/lib/pipeline/FetchUnit.cc | 12 ++-- test/unit/GenericPredictorTest.cc | 54 +++++++++--------- test/unit/PerceptronPredictorTest.cc | 56 ++++++++++--------- test/unit/aarch64/InstructionTest.cc | 12 ++-- test/unit/pipeline/FetchUnitTest.cc | 8 +-- test/unit/riscv/InstructionTest.cc | 12 ++-- 22 files changed, 154 insertions(+), 150 deletions(-) diff --git a/docs/sphinx/developer/arch/supported/aarch64.rst b/docs/sphinx/developer/arch/supported/aarch64.rst index 092264e991..6df0028e48 100644 --- a/docs/sphinx/developer/arch/supported/aarch64.rst +++ b/docs/sphinx/developer/arch/supported/aarch64.rst @@ -55,12 +55,12 @@ Additional information The ``FP`` primary identifier is a placeholder to denote both the ``SCALAR`` and ``VECTOR`` primary identifiers such that, amongst the other combinations, ``FP_SIMPLE_ARTH`` expands to be ``SCALAR_SIMPLE_ARTH`` and ``VECTOR_SIMPLE_ARTH``. In some cases it was unnecessary and inconvenient to separate ``SCALAR`` and ``VECTOR`` operations within configuration options, therefore, this instruction group option was provided to solve the issue. -When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is taken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. +When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is isTaken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. Instruction Splitting ********************* -Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is taken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: +Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is isTaken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: - Load pair for X/W/S/D/Q registers. diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index e2ff1d1ec1..b6a58d091a 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -30,13 +30,13 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. Static Prediction - Based on the chosen static prediction method of "always taken" or "always not taken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of taken or not-taken respectively. + Based on the chosen static prediction method of "always isTaken" or "always not isTaken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of isTaken or not-isTaken respectively. Perceptron Predictor -------------------- @@ -48,9 +48,9 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. - The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not taken if this is negative, or taken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. + The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not isTaken if this is negative, or isTaken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. \ No newline at end of file diff --git a/docs/sphinx/developer/components/coreinstance.rst b/docs/sphinx/developer/components/coreinstance.rst index 8b9e99a449..89b6247db4 100644 --- a/docs/sphinx/developer/components/coreinstance.rst +++ b/docs/sphinx/developer/components/coreinstance.rst @@ -3,7 +3,7 @@ Core Instance The ``CoreInstance`` component supplies the functionality for instantiating all simulation objects and linking them together. -The standard process taken to create an instance of the modelled core is as follows: +The standard process isTaken to create an instance of the modelled core is as follows: Process the config file Either the passed configuration file path, or default configuration string, is used to generate the model configuration class. All subsequent parameterised instantiations of simulation objects utilise this configuration class. diff --git a/docs/sphinx/developer/components/pipeline/components.rst b/docs/sphinx/developer/components/pipeline/components.rst index ab62a6b919..f74d5e892e 100644 --- a/docs/sphinx/developer/components/pipeline/components.rst +++ b/docs/sphinx/developer/components/pipeline/components.rst @@ -69,7 +69,7 @@ Once a completion slot is available, the load will be executed, the results broa Stores ****** -As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is taken from the ``storeQueue_`` entry. +As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is isTaken from the ``storeQueue_`` entry. The generation of store instruction write requests are carried out after its commitment. The reasoning for this design decision is as followed. With SimEng supporting speculative execution, processed store instruction may come from an incorrectly speculated branch direction and will inevitably be removed from the pipeline. Therefore, it is important to ensure any write requests are valid, concerning speculative execution, as the performance cost of reversing a completed write request is high. diff --git a/docs/sphinx/developer/components/pipeline/units.rst b/docs/sphinx/developer/components/pipeline/units.rst index 52358f4658..922b24f5a6 100644 --- a/docs/sphinx/developer/components/pipeline/units.rst +++ b/docs/sphinx/developer/components/pipeline/units.rst @@ -23,7 +23,7 @@ Behaviour The fetch unit fetches memory in discrete boundary-aligned blocks, according to the current program counter (PC); this is to prevent the fetched block overlapping an inaccessible or unmapped memory region that may result in the request incorrectly responding with a fault despite the validity of the initial region. -Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a taken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. +Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a isTaken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. This standard process of pre-decoding, predicting, and updating the PC continues until one of the following occurs: @@ -32,7 +32,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues The maximum number of fetched macro-ops is reached The current block is saved and processing resumes in the next cycle. - A branch is predicted as taken + A branch is predicted as isTaken A block of memory from the new address may be requested, and processing will resume once the data is available. The fetched memory block is exhausted @@ -43,7 +43,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues Loop Buffer *********** -Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is taken and increases the throughput of the fetch unit. +Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is isTaken and increases the throughput of the fetch unit. Each entry of the loop buffer is the encoding of the Macro-Op. Therefore, when supplying an instruction from the loop buffer, the pre-decoding step must still be performed. This was required to avoid any issues with multiple instantiations of the same instruction editing each others class members. @@ -59,7 +59,7 @@ FILLING The branch representing the loop has been found and the buffer is being filled until it is seen again. SUPPLYING - The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is taken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. + The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is isTaken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. The detection of a loop and the branch which represents it comes from the ROB. More information can be found :ref:`here `. @@ -81,7 +81,7 @@ Behaviour Each cycle, the decode unit will read macro-ops from the input buffer, and split them into a stream of ``Instruction`` objects or micro-ops. These ``Instruction`` objects are passed into an internal buffer. -Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a taken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. +Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a isTaken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. The cycle ends when all ``Instruction`` objects in the internal buffer have been processed, or a misprediction is identified and all remaining ``Instruction`` objects are flushed. diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/AlwaysNotTakenPredictor.hh index 7ec8027d4b..fc91e6d9ca 100644 --- a/src/include/simeng/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/AlwaysNotTakenPredictor.hh @@ -4,12 +4,12 @@ namespace simeng { -/** An "Always Not Taken" branch predictor; predicts all branches as not taken. +/** An "Always Not Taken" branch predictor; predicts all branches as not isTaken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will - * always predict not taken. */ + * always predict not isTaken. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset) override; @@ -19,7 +19,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { BranchType type) override; /** Provide flush logic for branch prediction scheme. As there's no flush - * logic for an always taken predictor, this does nothing. */ + * logic for an always isTaken predictor, this does nothing. */ void flush(uint64_t address) override; }; diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/BranchPredictor.hh index 1b62beea98..c4da8e1ff9 100644 --- a/src/include/simeng/BranchPredictor.hh +++ b/src/include/simeng/BranchPredictor.hh @@ -17,16 +17,16 @@ enum class BranchType { /** A branch result prediction for an instruction. */ struct BranchPrediction { - /** Whether the branch will be taken. */ - bool taken; + /** Whether the branch will be isTaken. */ + bool isTaken; - /** The branch instruction's target address. If `taken = false`, the value + /** The branch instruction's target address. If `isTaken = false`, the value * will be ignored. */ uint64_t target; /** Check for equality of two branch predictions . */ bool operator==(const BranchPrediction& other) { - if ((taken == other.taken) && (target == other.target)) + if ((isTaken == other.isTaken) && (target == other.target)) return true; else return false; @@ -34,7 +34,7 @@ struct BranchPrediction { /** Check for inequality of two branch predictions . */ bool operator!=(const BranchPrediction& other) { - if ((taken != other.taken) || (target != other.target)) + if ((isTaken != other.isTaken) || (target != other.target)) return true; else return false; @@ -54,7 +54,7 @@ class BranchPredictor { /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program * order */ - virtual void update(uint64_t address, bool taken, uint64_t targetAddress, + virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) = 0; /** Provides flushing behaviour for the implemented branch prediction schemes @@ -66,7 +66,7 @@ class BranchPredictor { /** Adds instruction to the Fetch Target Queue without making a new prediction */ - virtual void addToFTQ(uint64_t address, bool taken) = 0; + virtual void addToFTQ(uint64_t address, bool isTaken) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 24013efb85..7690c11b33 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -34,7 +34,7 @@ class GenericPredictor : public BranchPredictor { /** Updates appropriate predictor model objects based on the address and * outcome of the branch instruction. */ - void update(uint64_t address, bool taken, uint64_t targetAddress, + void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; /** Provides RAS rewinding behaviour. */ @@ -42,7 +42,7 @@ class GenericPredictor : public BranchPredictor { /** Adds instruction to the Fetch Target Queue without making a new prediction */ - void addToFTQ(uint64_t address, bool taken) override; + void addToFTQ(uint64_t address, bool isTaken) override; private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 0fbaa932d5..5fde93ab81 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -147,16 +147,16 @@ class Instruction { /** Retrieve branch address. */ uint64_t getBranchAddress() const { return branchAddress_; } - /** Was the branch taken? */ + /** Was the branch isTaken? */ bool wasBranchTaken() const { return branchTaken_; } /** Check for misprediction. */ bool wasBranchMispredicted() const { assert(executed_ && "Branch misprediction check requires instruction to have executed"); - // Flag as mispredicted if taken state was wrongly predicted, or taken and + // Flag as mispredicted if isTaken state was wrongly predicted, or isTaken and // predicted target is wrong - return (branchTaken_ != prediction_.taken || + return (branchTaken_ != prediction_.isTaken || (branchTaken_ && (prediction_.target != branchAddress_))); } diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 9fd040fa8e..9236e9e01e 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -37,7 +37,7 @@ class PerceptronPredictor : public BranchPredictor { /** Updates appropriate predictor model objects based on the address and * outcome of the branch instruction. */ - void update(uint64_t address, bool taken, uint64_t targetAddress, + void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; /** Provides RAS rewinding behaviour. */ @@ -45,7 +45,7 @@ class PerceptronPredictor : public BranchPredictor { /** Adds instruction to the Fetch Target Queue without making a new prediction */ - void addToFTQ(uint64_t address, bool taken) override; + void addToFTQ(uint64_t address, bool isTaken) override; private: /** Returns the dot product of a perceptron and a history vector. Used to diff --git a/src/include/simeng/arch/aarch64/helpers/conditional.hh b/src/include/simeng/arch/aarch64/helpers/conditional.hh index e541eb276a..2b3ea1b9c3 100644 --- a/src/include/simeng/arch/aarch64/helpers/conditional.hh +++ b/src/include/simeng/arch/aarch64/helpers/conditional.hh @@ -56,7 +56,7 @@ uint8_t ccmp_reg(srcValContainer& sourceValues, /** Helper function for instructions with the format `cb rn, #imm`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch taken, uint64_t address]. */ + * Returns tuple of type [bool branch isTaken, uint64_t address]. */ template std::tuple condBranch_cmpToZero( srcValContainer& sourceValues, @@ -91,7 +91,7 @@ T cs_4ops(srcValContainer& sourceValues, /** Helper function for instructions with the format `tb rn, #imm, * label`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch taken, uint64_t address]. */ + * Returns tuple of type [bool branch isTaken, uint64_t address]. */ template std::tuple tbnz_tbz( srcValContainer& sourceValues, diff --git a/src/include/simeng/config/yaml/ryml.hh b/src/include/simeng/config/yaml/ryml.hh index bed8f4620b..c35a4925f9 100644 --- a/src/include/simeng/config/yaml/ryml.hh +++ b/src/include/simeng/config/yaml/ryml.hh @@ -229,7 +229,7 @@ #define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch)) -/** A preprocessor foreach. Spectacular trick taken from: +/** A preprocessor foreach. Spectacular trick isTaken from: * http://stackoverflow.com/a/1872506/5875572 * The first argument is for a macro receiving a single argument, * which will be called with every subsequent argument. There is @@ -1449,7 +1449,7 @@ using std::index_sequence_for; /** C++11 implementation of integer sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template struct integer_sequence { @@ -1461,7 +1461,7 @@ struct integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence = integer_sequence; @@ -1544,19 +1544,19 @@ struct __make_integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_index_sequence = make_integer_sequence; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence_for = make_index_sequence; #endif @@ -4795,7 +4795,7 @@ namespace detail { /** @internal * @ingroup hash - * @see this was taken a great answer in stackoverflow: + * @see this was isTaken a great answer in stackoverflow: * https://stackoverflow.com/a/34597785/5875572 * @see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/ */ template @@ -12377,7 +12377,7 @@ inline size_t scan_one(csubstr str, const char *type_fmt, T *v) * * So we fake it by using a dynamic format with an explicit * field size set to the length of the given span. - * This trick is taken from: + * This trick is isTaken from: * https://stackoverflow.com/a/18368910/5875572 */ /* this is the actual format we'll use for scanning */ @@ -14624,7 +14624,7 @@ C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, substr buf, c namespace c4 { -//! taken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum +//! isTaken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum template using is_scoped_enum = std::integral_constant::value && !std::is_convertible::value>; @@ -15704,7 +15704,7 @@ template using cspanrs = spanrs; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- /** A non-owning span which always retains the capacity of the original - * range it was taken from (though it may loose its original size). + * range it was isTaken from (though it may loose its original size). * The resizing methods resize(), ltrim(), rtrim() as well * as the subselection methods subspan(), range(), first() and last() can be * used at will without loosing the original capacity; the full capacity span diff --git a/src/lib/GenericPredictor.cc b/src/lib/GenericPredictor.cc index 06875a51c5..99c0926426 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/GenericPredictor.cc @@ -11,8 +11,8 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) globalHistoryLength_( config["Branch-Predictor"]["Global-History-Length"].as()), rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { - // Calculate the saturation counter boundary between weakly taken and - // not-taken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly taken state + // Calculate the saturation counter boundary between weakly isTaken and + // not-isTaken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly isTaken state // value uint8_t weaklyTaken = 1 << (satCntBits_ - 1); uint8_t satCntVal = (config["Branch-Predictor"]["Fallback-Static-Predictor"] @@ -53,9 +53,9 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Amend prediction based on branch type if (type == BranchType::Unconditional) { - prediction.taken = true; + prediction.isTaken = true; } else if (type == BranchType::Return) { - prediction.taken = true; + prediction.isTaken = true; // Return branches can use the RAS if an entry is available if (ras_.size() > 0) { prediction.target = ras_.back(); @@ -64,7 +64,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, ras_.pop_back(); } } else if (type == BranchType::SubroutineCall) { - prediction.taken = true; + prediction.isTaken = true; // Subroutine call branches must push their associated return address to RAS if (ras_.size() >= rasSize_) { ras_.pop_front(); @@ -73,20 +73,20 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Record that this address is a branch-and-link instruction rasHistory_[address] = 0; } else if (type == BranchType::Conditional) { - if (!prediction.taken) prediction.target = address + 4; + if (!prediction.isTaken) prediction.target = address + 4; } // Store the hashed index for correct hashing in update() - ftq_.emplace_back(prediction.taken, hashedIndex); + ftq_.emplace_back(prediction.isTaken, hashedIndex); // Speculatively update the global history globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; return prediction; } -void GenericPredictor::update(uint64_t address, bool taken, +void GenericPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) { // Get previous prediction and index calculated from the FTQ bool prevPrediction = ftq_.front().first; @@ -96,16 +96,16 @@ void GenericPredictor::update(uint64_t address, bool taken, // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; // Only alter value if it would transition to a valid state - if (!((satCntVal == (1 << satCntBits_) - 1) && taken) && - !(satCntVal == 0 && !taken)) { - satCntVal += taken ? 1 : -1; + if (!((satCntVal == (1 << satCntBits_) - 1) && isTaken) && + !(satCntVal == 0 && !isTaken)) { + satCntVal += isTaken ? 1 : -1; } // Update BTB entry btb_[hashedIndex] = {satCntVal, targetAddress}; // Update global history if prediction was incorrect - if (prevPrediction != taken) { + if (prevPrediction != isTaken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ globalHistory_ ^= (1 << (ftq_.size())); @@ -141,13 +141,13 @@ void GenericPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void GenericPredictor::addToFTQ(uint64_t address, bool taken) { +void GenericPredictor::addToFTQ(uint64_t address, bool isTaken) { // Make the hashed index and add it to the FTQ uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - ftq_.emplace_back(taken, hashedIndex); + ftq_.emplace_back(isTaken, hashedIndex); // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; + globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; } } // namespace simeng diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/PerceptronPredictor.cc index 9acd49a4d8..e45cee47b0 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/PerceptronPredictor.cc @@ -21,7 +21,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Set up training threshold according to empirically determined formula trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); - globalHistoryMask_ = (globalHistoryLength_ * 2) - 1; + globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; } PerceptronPredictor::~PerceptronPredictor() { @@ -56,9 +56,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Amend prediction based on branch type if (type == BranchType::Unconditional) { - prediction.taken = true; + prediction.isTaken = true; } else if (type == BranchType::Return) { - prediction.taken = true; + prediction.isTaken = true; // Return branches can use the RAS if an entry is available if (ras_.size() > 0) { prediction.target = ras_.back(); @@ -67,7 +67,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, ras_.pop_back(); } } else if (type == BranchType::SubroutineCall) { - prediction.taken = true; + prediction.isTaken = true; // Subroutine call branches must push their associated return address to RAS if (ras_.size() >= rasSize_) { ras_.pop_front(); @@ -76,22 +76,22 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Record that this address is a branch-and-link instruction rasHistory_[address] = 0; } else if (type == BranchType::Conditional) { - if (!prediction.taken) prediction.target = address + 4; + if (!prediction.isTaken) prediction.target = address + 4; } // Store the global history for correct hashing in update() -- // needs to be global history and not the hashed index as hashing loses // information at longer global history lengths - ftq_.emplace_back(prediction.taken, globalHistory_); + ftq_.emplace_back(prediction.isTaken, globalHistory_); // speculatively update global history globalHistory_ = - ((globalHistory_ << 1) | prediction.taken) & globalHistoryMask_; + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; return prediction; } -void PerceptronPredictor::update(uint64_t address, bool taken, +void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) { // Get previous branch state and prediction from FTQ bool prevPrediction = ftq_.front().first; @@ -110,6 +110,8 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update the perceptron if the prediction was wrong, or the dot product's // magnitude was not greater than the training threshold + if ((directionPrediction != isTaken) || (abs(Pout) < trainingThreshold_)) { + int8_t t = (isTaken) ? 1 : -1; if ((directionPrediction != taken) || (static_cast(std::abs(Pout)) < trainingThreshold_)) { int8_t t = (taken) ? 1 : -1; @@ -135,7 +137,7 @@ void PerceptronPredictor::update(uint64_t address, bool taken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (prevPrediction != taken) globalHistory_ ^= (1 << (ftq_.size())); + if (prevPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -166,10 +168,10 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void PerceptronPredictor::addToFTQ(uint64_t address, bool taken) { +void PerceptronPredictor::addToFTQ(uint64_t address, bool isTaken) { // Add instruction to the FTQ in event of reused prediction - ftq_.emplace_back(taken, globalHistory_); - globalHistory_ = ((globalHistory_ << 1) | taken) & globalHistoryMask_; + ftq_.emplace_back(isTaken, globalHistory_); + globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; } int64_t PerceptronPredictor::getDotProduct( diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 13c75117df..1bf93c451f 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -106,9 +106,9 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as taken, it will require a + // Instruction isn't a branch; if predicted as isTaken, it will require a // flush - return {prediction_.taken, instructionAddress_ + 4}; + return {prediction_.isTaken, instructionAddress_ + 4}; } // Not enough information to determine this was a misprediction diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index 29c4793c44..5eb1091c6b 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -101,9 +101,9 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as taken, it will require a + // Instruction isn't a branch; if predicted as isTaken, it will require a // flush - return {prediction_.taken, instructionAddress_ + 4}; + return {prediction_.isTaken, instructionAddress_ + 4}; } // Not enough information to determine this was a misprediction diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 95df50ce7b..706261edc1 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -56,7 +56,7 @@ void FetchUnit::tick() { // Let the branch predictor know the prediction is being reused so that // the FTQ can be kept up to date branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchPrediction().taken); + macroOp[0]->getBranchPrediction().isTaken); branchesExecuted_++; } @@ -165,7 +165,7 @@ void FetchUnit::tick() { if (pc_ == loopBoundaryAddress_) { if (macroOp[0]->isBranch() && - !macroOp[0]->getBranchPrediction().taken) { + !macroOp[0]->getBranchPrediction().isTaken) { // loopBoundaryAddress_ has been fetched whilst filling the loop // buffer BUT this is a branch, predicted to branch out of the loop // being buffered. Stop filling the loop buffer and don't supply to @@ -202,11 +202,11 @@ void FetchUnit::tick() { bufferOffset += bytesRead; bufferedBytes_ -= bytesRead; - if (!prediction.taken) { - // Predicted as not taken; increment PC to next instruction + if (!prediction.isTaken) { + // Predicted as not isTaken; increment PC to next instruction pc_ += bytesRead; } else { - // Predicted as taken; set PC to predicted target address + // Predicted as isTaken; set PC to predicted target address pc_ = prediction.target; } @@ -215,7 +215,7 @@ void FetchUnit::tick() { break; } - if (prediction.taken) { + if (prediction.isTaken) { if (slot + 1 < output_.getWidth()) { branchStalls_++; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 2fe34f48a3..6f1db4f449 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -24,7 +24,7 @@ TEST_F(GenericPredictorTest, Miss) { "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); simeng::config::SimInfo::addToConfig( "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 11, " @@ -32,9 +32,9 @@ TEST_F(GenericPredictorTest, Miss) { "Fallback-Static-Predictor: Always-Not-Taken}}"); predictor = simeng::GenericPredictor(); prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); prediction = predictor.predict(8, BranchType::Unconditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); } // Tests that a GenericPredictor will predict branch-and-link return pairs @@ -46,35 +46,35 @@ TEST_F(GenericPredictorTest, RAS) { "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); prediction = predictor.predict(56, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 64); prediction = predictor.predict(72, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 80); prediction = predictor.predict(84, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 76); prediction = predictor.predict(68, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 60); prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -98,7 +98,7 @@ TEST_F(GenericPredictorTest, Hit) { predictor.update(0, true, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); } @@ -133,7 +133,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB predictor.update(0x7C, true, 0xAB, BranchType::Conditional); @@ -161,7 +161,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB predictor.update(0x7C, true, 0xBA, BranchType::Conditional); @@ -189,7 +189,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB predictor.update(0x7C, true, 0xAB, BranchType::Conditional); @@ -217,7 +217,7 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } @@ -231,21 +231,21 @@ TEST_F(GenericPredictorTest, flush) { auto predictor = simeng::GenericPredictor(); // Add some entries to the RAS auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); // Start getting entries from RAS prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); // Flush address @@ -253,10 +253,10 @@ TEST_F(GenericPredictorTest, flush) { // Continue getting entries from RAS prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(16, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -282,7 +282,7 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x4); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); @@ -302,7 +302,7 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 70485355dd..e8ce9d5747 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -23,9 +23,9 @@ TEST_F(PerceptronPredictorTest, Miss) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); prediction = predictor.predict(8, BranchType::Unconditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); } // Tests that the PerceptronPredictor will predict branch-and-link return pairs @@ -36,35 +36,35 @@ TEST_F(PerceptronPredictorTest, RAS) { "Global-History-Length: 10, RAS-entries: 10}}"); auto predictor = simeng::PerceptronPredictor(); auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); prediction = predictor.predict(56, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 64); prediction = predictor.predict(72, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 80); prediction = predictor.predict(84, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 76); prediction = predictor.predict(68, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 60); prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -87,7 +87,7 @@ TEST_F(PerceptronPredictorTest, Hit) { predictor.update(0, true, 16, BranchType::Conditional); auto prediction = predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); } @@ -121,7 +121,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB predictor.update(0x7C, false, 0x80, BranchType::Conditional); @@ -149,7 +149,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB predictor.update(0x7C, true, 0xBA, BranchType::Conditional); @@ -177,7 +177,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_FALSE(prediction.taken); + EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB predictor.update(0x7C, true, 0x80, BranchType::Conditional); @@ -205,7 +205,7 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); predictor.update(0x7C, true, 0xBA, BranchType::Conditional); } @@ -218,21 +218,21 @@ TEST_F(PerceptronPredictorTest, flush) { auto predictor = simeng::PerceptronPredictor(); // Add some entries to the RAS auto prediction = predictor.predict(8, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 16); prediction = predictor.predict(24, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 32); prediction = predictor.predict(40, BranchType::SubroutineCall, 8); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 48); // Start getting entries from RAS prediction = predictor.predict(52, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 44); prediction = predictor.predict(36, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); // Flush address @@ -240,10 +240,10 @@ TEST_F(PerceptronPredictorTest, flush) { // Continue getting entries from RAS prediction = predictor.predict(20, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 28); prediction = predictor.predict(16, BranchType::Return, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 12); } @@ -268,8 +268,10 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); - EXPECT_EQ(prediction.target, 0x4); + // Defaults to not-taken + EXPECT_FALSE(prediction.isTaken); + // Should predict target of address + 4 + EXPECT_EQ(prediction.target, 0x103); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); @@ -288,7 +290,7 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0, true, 4, BranchType::Conditional); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.taken); + EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB predictor.update(0xFF, true, 0xAB, BranchType::Conditional); diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 92b8e9393a..00279300b8 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -493,7 +493,7 @@ TEST_F(AArch64InstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch taken) is handled correctly +// Test that a correct prediction (branch isTaken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -510,7 +510,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is taken is handled correctly + // Test a correct prediction where branch is isTaken is handled correctly pred = {true, 80 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -522,7 +522,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not taken) is handled correctly +// Test that a correct prediction (branch not isTaken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_notTaken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -539,7 +539,7 @@ TEST_F(AArch64InstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't taken is handled correctly + // Test a correct prediction where a branch isn't isTaken is handled correctly pred = {false, 80 + 4}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -580,7 +580,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 100 + 0x28); } -// Test that an incorrect prediction (wrong taken) is handled correctly +// Test that an incorrect prediction (wrong isTaken) is handled correctly TEST_F(AArch64InstructionTest, incorrectPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -597,7 +597,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - taken is wrong + // Test an incorrect prediction is handled correctly - isTaken is wrong pred = {true, 100 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 8ecdc7d88b..a9b8c07084 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -232,7 +232,7 @@ TEST_P(PipelineFetchUnitTest, halted) { EXPECT_TRUE(fetchUnit.hasHalted()); } -// Tests that fetching a branch instruction (predicted taken) mid block causes a +// Tests that fetching a branch instruction (predicted isTaken) mid block causes a // branch stall + discards the remaining fetched instructions TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { const uint8_t pc = 16; @@ -266,7 +266,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); fetchUnit.tick(); - // For second tick, process a taken branch meaning rest of block is discarded + // For second tick, process a isTaken branch meaning rest of block is discarded // & a new memory block is requested EXPECT_CALL(memory, getCompletedReads()).Times(0); EXPECT_CALL(memory, clearCompletedReads()).Times(1); @@ -388,7 +388,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { } // Tests the functionality of idling the supply to the Loop Buffer one of not -// taken branch at the loopBoundaryAddress_ +// isTaken branch at the loopBoundaryAddress_ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set instructions to be fetched from memory memory::MemoryReadResult memReadResultA = { @@ -432,7 +432,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); - // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the + // Attempt to fill Loop Buffer but prevent it on a not isTaken outcome at the // loopBoundaryAddress_ branch // Tick 4 times to process all 16 bytes of fetched data for (int i = 0; i < 4; i++) { diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index 6103cd4f5c..c40b503a6c 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -467,7 +467,7 @@ TEST_F(RiscVInstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch taken) is handled correctly +// Test that a correct prediction (branch isTaken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -484,7 +484,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is taken is handled correctly + // Test a correct prediction where branch is isTaken is handled correctly pred = {true, 400 - 86}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -497,7 +497,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not taken) is handled correctly +// Test that a correct prediction (branch not isTaken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_notTaken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -514,7 +514,7 @@ TEST_F(RiscVInstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't taken is handled correctly + // Test a correct prediction where a branch isn't isTaken is handled correctly // imm operand 0x28 has 4 added implicitly by dissassembler pred = {false, 400 + 4}; insn.setBranchPrediction(pred); @@ -559,7 +559,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 400 - 86); } -// Test that an incorrect prediction (wrong taken) is handled correctly +// Test that an incorrect prediction (wrong isTaken) is handled correctly TEST_F(RiscVInstructionTest, incorrectPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -576,7 +576,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - taken is wrong + // Test an incorrect prediction is handled correctly - isTaken is wrong // imm operand 0x28 has 4 added implicitly by dissassembler pred = {true, 400 - 86}; insn.setBranchPrediction(pred); From 83185ca68586bbcdee60425aa8690128a059329f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:06:56 +0100 Subject: [PATCH 120/191] Adding comments explaining more basically the nature of the global history --- src/include/simeng/GenericPredictor.hh | 5 +++-- src/include/simeng/PerceptronPredictor.hh | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/GenericPredictor.hh index 7690c11b33..d004daf412 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/GenericPredictor.hh @@ -59,8 +59,9 @@ class GenericPredictor : public BranchPredictor { /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; - /** A n-bit history of previous branch directions where n is equal to - * globalHistoryLength_. */ + /** An n-bit history of previous branch directions where n is equal to + * globalHistoryLength_. Each bit represents a branch taken (1) or not + * taken (0), with the most recent branch being the least-significant-bit */ uint64_t globalHistory_ = 0; /** The number of previous branch directions recorded globally. */ diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/PerceptronPredictor.hh index 9236e9e01e..167931372f 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/PerceptronPredictor.hh @@ -68,7 +68,8 @@ class PerceptronPredictor : public BranchPredictor { std::deque> ftq_; /** An n-bit history of previous branch directions where n is equal to - * globalHistoryLength_. */ + * globalHistoryLength_. Each bit represents a branch taken (1) or not + * taken (0), with the most recent branch being the least-significant-bit */ uint64_t globalHistory_ = 0; /** The number of previous branch directions recorded globally. */ From 6599dd297175fd154e6fb54cabf864effa8dd0b0 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:18:38 +0100 Subject: [PATCH 121/191] replacing top/bottom with front/back in the docs when referring to a queue --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index b6a58d091a..5dcd3eb69b 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,7 +17,7 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the top of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the bottom of the queue on ``update`` and from the top of the queue on ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the front of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the back of the queue on ``update`` and from the front of the queue on ``flush``. Generic Predictor ----------------- From 4bb71f45a377189be0993cd759aae12e07bbddc3 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:20:45 +0100 Subject: [PATCH 122/191] Replacing left-most with most-significant --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 5dcd3eb69b..58b3eeaaf9 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. From cc773c487c1b886f9e8c5cc821f72d4d549556c3 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 09:27:48 +0100 Subject: [PATCH 123/191] Replacing left-most with most-significant --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 58b3eeaaf9..e170afe262 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the left-most bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. From c0b9351ecdea78583f4fc809554ba0ac52a26748 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 13:51:38 +0100 Subject: [PATCH 124/191] Moving BP files to new directory --- src/include/simeng/AlwaysNotTakenPredictor.hh | 2 +- src/include/simeng/CoreInstance.hh | 4 ++-- src/include/simeng/Instruction.hh | 2 +- src/include/simeng/arch/Architecture.hh | 2 +- src/include/simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 2 +- src/include/simeng/{ => branchPredictors}/BranchPredictor.hh | 0 src/include/simeng/{ => branchPredictors}/GenericPredictor.hh | 2 +- .../simeng/{ => branchPredictors}/PerceptronPredictor.hh | 2 +- src/include/simeng/pipeline/ExecuteUnit.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 2 +- src/lib/CMakeLists.txt | 4 ++-- src/lib/{ => branchPredictors}/GenericPredictor.cc | 2 +- src/lib/{ => branchPredictors}/PerceptronPredictor.cc | 2 +- test/regression/RegressionTest.cc | 4 ++-- test/unit/GenericPredictorTest.cc | 2 +- test/unit/MockBranchPredictor.hh | 2 +- test/unit/PerceptronPredictorTest.cc | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) rename src/include/simeng/{ => branchPredictors}/BranchPredictor.hh (100%) rename src/include/simeng/{ => branchPredictors}/GenericPredictor.hh (98%) rename src/include/simeng/{ => branchPredictors}/PerceptronPredictor.hh (98%) rename src/lib/{ => branchPredictors}/GenericPredictor.cc (99%) rename src/lib/{ => branchPredictors}/PerceptronPredictor.cc (99%) diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/AlwaysNotTakenPredictor.hh index fc91e6d9ca..fa05ca8ca9 100644 --- a/src/include/simeng/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/AlwaysNotTakenPredictor.hh @@ -1,6 +1,6 @@ #pragma once -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index 2dc064fa50..a2aa259b57 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -5,12 +5,12 @@ #include "simeng/AlwaysNotTakenPredictor.hh" #include "simeng/Core.hh" #include "simeng/Elf.hh" -#include "simeng/GenericPredictor.hh" -#include "simeng/PerceptronPredictor.hh" #include "simeng/SpecialFileDirGen.hh" #include "simeng/arch/Architecture.hh" #include "simeng/arch/aarch64/Architecture.hh" #include "simeng/arch/riscv/Architecture.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/FixedLatencyMemoryInterface.hh" diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 5fde93ab81..4c6b196051 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -3,7 +3,7 @@ #include #include "capstone/capstone.h" -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" #include "simeng/memory/MemoryInterface.hh" diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 70782c079c..3b5a1b4fe2 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -3,7 +3,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Core.hh" #include "simeng/Instruction.hh" #include "simeng/arch/ProcessStateChange.hh" diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 315a555a00..c223ed33ce 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -3,7 +3,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/aarch64/InstructionGroups.hh" #include "simeng/arch/aarch64/operandContainer.hh" diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index 888900ba18..dfb6639fcc 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -5,7 +5,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/riscv/InstructionGroups.hh" diff --git a/src/include/simeng/BranchPredictor.hh b/src/include/simeng/branchPredictors/BranchPredictor.hh similarity index 100% rename from src/include/simeng/BranchPredictor.hh rename to src/include/simeng/branchPredictors/BranchPredictor.hh diff --git a/src/include/simeng/GenericPredictor.hh b/src/include/simeng/branchPredictors/GenericPredictor.hh similarity index 98% rename from src/include/simeng/GenericPredictor.hh rename to src/include/simeng/branchPredictors/GenericPredictor.hh index d004daf412..a288583746 100644 --- a/src/include/simeng/GenericPredictor.hh +++ b/src/include/simeng/branchPredictors/GenericPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { diff --git a/src/include/simeng/PerceptronPredictor.hh b/src/include/simeng/branchPredictors/PerceptronPredictor.hh similarity index 98% rename from src/include/simeng/PerceptronPredictor.hh rename to src/include/simeng/branchPredictors/PerceptronPredictor.hh index 167931372f..c846d045cf 100644 --- a/src/include/simeng/PerceptronPredictor.hh +++ b/src/include/simeng/branchPredictors/PerceptronPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index c803476873..66433e05d2 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -3,7 +3,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/pipeline/PipelineBuffer.hh" diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index b65d21c61a..2799d54fa9 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { namespace pipeline { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ffabd8bbca..2930f2b1b8 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,6 +14,8 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc + branchPredictors/GenericPredictor.cc + branchPredictors/PerceptronPredictor.cc config/ModelConfig.cc kernel/Linux.cc kernel/LinuxProcess.cc @@ -40,8 +42,6 @@ set(SIMENG_SOURCES CMakeLists.txt CoreInstance.cc Elf.cc - GenericPredictor.cc - PerceptronPredictor.cc RegisterFileSet.cc RegisterValue.cc SpecialFileDirGen.cc diff --git a/src/lib/GenericPredictor.cc b/src/lib/branchPredictors/GenericPredictor.cc similarity index 99% rename from src/lib/GenericPredictor.cc rename to src/lib/branchPredictors/GenericPredictor.cc index 99c0926426..9092f73d52 100644 --- a/src/lib/GenericPredictor.cc +++ b/src/lib/branchPredictors/GenericPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/GenericPredictor.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" #include diff --git a/src/lib/PerceptronPredictor.cc b/src/lib/branchPredictors/PerceptronPredictor.cc similarity index 99% rename from src/lib/PerceptronPredictor.cc rename to src/lib/branchPredictors/PerceptronPredictor.cc index e45cee47b0..8336d62772 100644 --- a/src/lib/PerceptronPredictor.cc +++ b/src/lib/branchPredictors/PerceptronPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/PerceptronPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" namespace simeng { diff --git a/test/regression/RegressionTest.cc b/test/regression/RegressionTest.cc index d4bf8e3a42..d1502344b1 100644 --- a/test/regression/RegressionTest.cc +++ b/test/regression/RegressionTest.cc @@ -2,8 +2,8 @@ #include -#include "simeng/GenericPredictor.hh" -#include "simeng/PerceptronPredictor.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/kernel/LinuxProcess.hh" diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 6f1db4f449..b24fbee3ff 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/GenericPredictor.hh" +#include "simeng/branchPredictors/GenericPredictor.hh" namespace simeng { diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index a6db5caceb..f09444165d 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -1,7 +1,7 @@ #pragma once #include "gmock/gmock.h" -#include "simeng/BranchPredictor.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index e8ce9d5747..40a36882b7 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/PerceptronPredictor.hh" +#include "simeng/branchPredictors/PerceptronPredictor.hh" namespace simeng { From 8a690dea2dc9dd00ebfc08424d6020c1d0b10985 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 13:54:38 +0100 Subject: [PATCH 125/191] Moving AlwaysNotTakenPredictor files to BP directory --- src/include/simeng/CoreInstance.hh | 2 +- .../simeng/{ => branchPredictors}/AlwaysNotTakenPredictor.hh | 0 src/lib/CMakeLists.txt | 2 +- src/lib/{ => branchPredictors}/AlwaysNotTakenPredictor.cc | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/include/simeng/{ => branchPredictors}/AlwaysNotTakenPredictor.hh (100%) rename src/lib/{ => branchPredictors}/AlwaysNotTakenPredictor.cc (86%) diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index a2aa259b57..2e3f5c6345 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -2,7 +2,7 @@ #include -#include "simeng/AlwaysNotTakenPredictor.hh" +#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" #include "simeng/Core.hh" #include "simeng/Elf.hh" #include "simeng/SpecialFileDirGen.hh" diff --git a/src/include/simeng/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh similarity index 100% rename from src/include/simeng/AlwaysNotTakenPredictor.hh rename to src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 2930f2b1b8..08cf1031bf 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -37,7 +37,7 @@ set(SIMENG_SOURCES pipeline/RenameUnit.cc pipeline/ReorderBuffer.cc pipeline/WritebackUnit.cc - AlwaysNotTakenPredictor.cc + branchPredictors/AlwaysNotTakenPredictor.cc ArchitecturalRegisterFileSet.cc CMakeLists.txt CoreInstance.cc diff --git a/src/lib/AlwaysNotTakenPredictor.cc b/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc similarity index 86% rename from src/lib/AlwaysNotTakenPredictor.cc rename to src/lib/branchPredictors/AlwaysNotTakenPredictor.cc index b7f33e6c22..d3f910283b 100644 --- a/src/lib/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/AlwaysNotTakenPredictor.hh" +#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" namespace simeng { From 23fd3d926436ed748472a774ec142e3b3d7e4b14 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 1 May 2024 17:03:28 +0100 Subject: [PATCH 126/191] clangformat and undoing some unintended taken -> isTaken --- .../developer/arch/supported/aarch64.rst | 4 ++-- .../developer/components/branchPred.rst | 8 ++++---- .../developer/components/coreinstance.rst | 2 +- .../components/pipeline/components.rst | 2 +- .../developer/components/pipeline/units.rst | 10 +++++----- src/include/simeng/CoreInstance.hh | 2 +- src/include/simeng/Instruction.hh | 8 ++++---- src/include/simeng/arch/Architecture.hh | 2 +- .../simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 2 +- .../AlwaysNotTakenPredictor.hh | 7 ++++--- .../branchPredictors/BranchPredictor.hh | 2 +- src/include/simeng/config/yaml/ryml.hh | 20 +++++++++---------- src/include/simeng/pipeline/ExecuteUnit.hh | 2 +- src/lib/CMakeLists.txt | 2 +- src/lib/arch/aarch64/Instruction.cc | 2 +- src/lib/arch/riscv/Instruction.cc | 2 +- src/lib/branchPredictors/GenericPredictor.cc | 8 ++++---- src/lib/pipeline/FetchUnit.cc | 4 ++-- test/unit/aarch64/InstructionTest.cc | 12 +++++------ test/unit/pipeline/FetchUnitTest.cc | 8 ++++---- test/unit/riscv/InstructionTest.cc | 12 +++++------ 22 files changed, 62 insertions(+), 61 deletions(-) diff --git a/docs/sphinx/developer/arch/supported/aarch64.rst b/docs/sphinx/developer/arch/supported/aarch64.rst index 6df0028e48..092264e991 100644 --- a/docs/sphinx/developer/arch/supported/aarch64.rst +++ b/docs/sphinx/developer/arch/supported/aarch64.rst @@ -55,12 +55,12 @@ Additional information The ``FP`` primary identifier is a placeholder to denote both the ``SCALAR`` and ``VECTOR`` primary identifiers such that, amongst the other combinations, ``FP_SIMPLE_ARTH`` expands to be ``SCALAR_SIMPLE_ARTH`` and ``VECTOR_SIMPLE_ARTH``. In some cases it was unnecessary and inconvenient to separate ``SCALAR`` and ``VECTOR`` operations within configuration options, therefore, this instruction group option was provided to solve the issue. -When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is isTaken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. +When setting the latencies for instruction groups, within the :ref:`Latencies ` section of the configurable options, the inheritance between instruction groups is taken into account (e.g. the ``VECTOR`` group latency assignment would be inherited by all ``VECTOR_*`` groups). If multiple entries could assign a latency value to an instruction group, the option with the least levels of inheritance to the instruction group takes priority. As an example, take the groups ``INT_SIMPLE`` and ``INT_SIMPLE_ARTH``. ``INT_SIMPLE_ARTH_NOSHIFT`` inherits from both of these groups but because ``INT_SIMPLE_ARTH`` has one less level of inheritance to traverse, ``INT_SIMPLE_ARTH_NOSHIFT`` inherits ``INT_SIMPLE_ARTH`` latency values. Instruction Splitting ********************* -Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is isTaken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: +Instruction splitting is performed within the ``decode`` function in ``MicroDecoder.cc``. A macro-op is taken into the ``decode`` function and one or more micro-ops, taking the form of SimEng ``Instruction`` objects, are returned. The following instruction splitting is supported: - Load pair for X/W/S/D/Q registers. diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index e170afe262..63cdc8d899 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -30,13 +30,13 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. Static Prediction - Based on the chosen static prediction method of "always isTaken" or "always not isTaken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of isTaken or not-isTaken respectively. + Based on the chosen static prediction method of "always taken" or "always not taken", the n-bit saturating counter value in the initial entries of the BTB structure are filled with the weakest variant of taken or not-taken respectively. Perceptron Predictor -------------------- @@ -48,9 +48,9 @@ Global History Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. - The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not isTaken if this is negative, or isTaken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. + The direction prediction is obtained from the perceptron by taking its dot-product with the global history. The prediction is not taken if this is negative, or taken otherwise. The perceptron is updated when its prediction is wrong or when the magnitude of the dot-product is below a pre-determined threshold (i.e., the confidence of the prediction is low). To update, each ith weight of the perceptron is incremented if the actual outcome of the branch is the same as the ith bit of ``globalHistory_``, and decremented otherwise. - If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be isTaken. If the supplied branch type is ``Conditional`` and the predicted direction is not isTaken, then the predicted target is overridden to be the next sequential instruction. + If the supplied branch type is ``Unconditional``, then the predicted direction is overridden to be taken. If the supplied branch type is ``Conditional`` and the predicted direction is not taken, then the predicted target is overridden to be the next sequential instruction. Return Address Stack (RAS) Identified through the supplied branch type, Return instructions pop values off of the RAS to get their branch target whilst Branch-and-Link instructions push values onto the RAS, for later use by the Branch-and-Link instruction's corresponding Return instruction. \ No newline at end of file diff --git a/docs/sphinx/developer/components/coreinstance.rst b/docs/sphinx/developer/components/coreinstance.rst index 89b6247db4..8b9e99a449 100644 --- a/docs/sphinx/developer/components/coreinstance.rst +++ b/docs/sphinx/developer/components/coreinstance.rst @@ -3,7 +3,7 @@ Core Instance The ``CoreInstance`` component supplies the functionality for instantiating all simulation objects and linking them together. -The standard process isTaken to create an instance of the modelled core is as follows: +The standard process taken to create an instance of the modelled core is as follows: Process the config file Either the passed configuration file path, or default configuration string, is used to generate the model configuration class. All subsequent parameterised instantiations of simulation objects utilise this configuration class. diff --git a/docs/sphinx/developer/components/pipeline/components.rst b/docs/sphinx/developer/components/pipeline/components.rst index f74d5e892e..ab62a6b919 100644 --- a/docs/sphinx/developer/components/pipeline/components.rst +++ b/docs/sphinx/developer/components/pipeline/components.rst @@ -69,7 +69,7 @@ Once a completion slot is available, the load will be executed, the results broa Stores ****** -As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is isTaken from the ``storeQueue_`` entry. +As with loads, stores are considered pending when initially added to the LSQ. Whilst like load operations the generation of addresses to be accessed must occur before commitment, an additional operation of supplying the data to be stored must also occur. The ``supplyStoreData`` function facilitates this by placing the data to be stored within the ``storeQueue_`` entry of the associated store. Once the store is committed, the data is taken from the ``storeQueue_`` entry. The generation of store instruction write requests are carried out after its commitment. The reasoning for this design decision is as followed. With SimEng supporting speculative execution, processed store instruction may come from an incorrectly speculated branch direction and will inevitably be removed from the pipeline. Therefore, it is important to ensure any write requests are valid, concerning speculative execution, as the performance cost of reversing a completed write request is high. diff --git a/docs/sphinx/developer/components/pipeline/units.rst b/docs/sphinx/developer/components/pipeline/units.rst index 922b24f5a6..52358f4658 100644 --- a/docs/sphinx/developer/components/pipeline/units.rst +++ b/docs/sphinx/developer/components/pipeline/units.rst @@ -23,7 +23,7 @@ Behaviour The fetch unit fetches memory in discrete boundary-aligned blocks, according to the current program counter (PC); this is to prevent the fetched block overlapping an inaccessible or unmapped memory region that may result in the request incorrectly responding with a fault despite the validity of the initial region. -Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a isTaken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. +Each cycle, it will process the most recently fetched memory block by passing it to the supplied ``Architecture`` instance for pre-decoding into macro-ops. Once pre-decoded, the head of the vector of micro-ops, or macro-op, is passed to the supplied branch predictor. If the instruction is predicted to be a taken branch, then the PC will be updated to the predicted target address and the cycle will end. If this is not the case, the PC is incremented by the number of bytes consumed to produce the pre-decoded macro-op. The remaining bytes in the block are once again passed to the architecture for pre-decoding. This standard process of pre-decoding, predicting, and updating the PC continues until one of the following occurs: @@ -32,7 +32,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues The maximum number of fetched macro-ops is reached The current block is saved and processing resumes in the next cycle. - A branch is predicted as isTaken + A branch is predicted as taken A block of memory from the new address may be requested, and processing will resume once the data is available. The fetched memory block is exhausted @@ -43,7 +43,7 @@ This standard process of pre-decoding, predicting, and updating the PC continues Loop Buffer *********** -Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is isTaken and increases the throughput of the fetch unit. +Within the fetch unit is a loop buffer that can store a configurable number of Macro-Ops. The loop buffer can be pulled from instead of memory if a loop is detected. This avoids the need to re-request data from memory if a branch is taken and increases the throughput of the fetch unit. Each entry of the loop buffer is the encoding of the Macro-Op. Therefore, when supplying an instruction from the loop buffer, the pre-decoding step must still be performed. This was required to avoid any issues with multiple instantiations of the same instruction editing each others class members. @@ -59,7 +59,7 @@ FILLING The branch representing the loop has been found and the buffer is being filled until it is seen again. SUPPLYING - The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is isTaken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. + The supply of instructions from the fetch unit has been handed over to the loop buffer. The stream of instructions is taken from the loop buffer in order and resets to the top of the buffer once it reaches the end of the loop body. The detection of a loop and the branch which represents it comes from the ROB. More information can be found :ref:`here `. @@ -81,7 +81,7 @@ Behaviour Each cycle, the decode unit will read macro-ops from the input buffer, and split them into a stream of ``Instruction`` objects or micro-ops. These ``Instruction`` objects are passed into an internal buffer. -Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a isTaken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. +Once all macro-ops in the input buffer have been passed into the internal ``Instruction`` buffer or the ``Instruction`` buffer size exceeds the size of the output buffer, ``Instruction`` objects are checked for any trivially identifiable branch mispredictions (i.e., a non-branch predicted as a taken branch), and if discovered, the branch predictor is informed and a pipeline flush requested. The cycle ends when all ``Instruction`` objects in the internal buffer have been processed, or a misprediction is identified and all remaining ``Instruction`` objects are flushed. diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index 2e3f5c6345..b66519bf64 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -2,13 +2,13 @@ #include -#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" #include "simeng/Core.hh" #include "simeng/Elf.hh" #include "simeng/SpecialFileDirGen.hh" #include "simeng/arch/Architecture.hh" #include "simeng/arch/aarch64/Architecture.hh" #include "simeng/arch/riscv/Architecture.hh" +#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" #include "simeng/branchPredictors/GenericPredictor.hh" #include "simeng/branchPredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 4c6b196051..c28f2177c3 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -3,9 +3,9 @@ #include #include "capstone/capstone.h" -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/memory/MemoryInterface.hh" #include "simeng/span.hh" @@ -147,15 +147,15 @@ class Instruction { /** Retrieve branch address. */ uint64_t getBranchAddress() const { return branchAddress_; } - /** Was the branch isTaken? */ + /** Was the branch taken? */ bool wasBranchTaken() const { return branchTaken_; } /** Check for misprediction. */ bool wasBranchMispredicted() const { assert(executed_ && "Branch misprediction check requires instruction to have executed"); - // Flag as mispredicted if isTaken state was wrongly predicted, or isTaken and - // predicted target is wrong + // Flag as mispredicted if taken state was wrongly predicted, or taken + // and predicted target is wrong return (branchTaken_ != prediction_.isTaken || (branchTaken_ && (prediction_.target != branchAddress_))); } diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 3b5a1b4fe2..1a28a0bd08 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -3,10 +3,10 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Core.hh" #include "simeng/Instruction.hh" #include "simeng/arch/ProcessStateChange.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/MemoryInterface.hh" diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index c223ed33ce..7bf9341ded 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -3,10 +3,10 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/aarch64/InstructionGroups.hh" #include "simeng/arch/aarch64/operandContainer.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" struct cs_arm64_op; diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index dfb6639fcc..69257153d8 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -5,9 +5,9 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" #include "simeng/arch/riscv/InstructionGroups.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" namespace simeng { namespace arch { diff --git a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh index fa05ca8ca9..b43c361e54 100644 --- a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh @@ -4,12 +4,13 @@ namespace simeng { -/** An "Always Not Taken" branch predictor; predicts all branches as not isTaken. +/** An "Always Not Taken" branch predictor; predicts all branches as not + * taken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will - * always predict not isTaken. */ + * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset) override; @@ -19,7 +20,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { BranchType type) override; /** Provide flush logic for branch prediction scheme. As there's no flush - * logic for an always isTaken predictor, this does nothing. */ + * logic for an always taken predictor, this does nothing. */ void flush(uint64_t address) override; }; diff --git a/src/include/simeng/branchPredictors/BranchPredictor.hh b/src/include/simeng/branchPredictors/BranchPredictor.hh index c4da8e1ff9..2bcf76eb25 100644 --- a/src/include/simeng/branchPredictors/BranchPredictor.hh +++ b/src/include/simeng/branchPredictors/BranchPredictor.hh @@ -17,7 +17,7 @@ enum class BranchType { /** A branch result prediction for an instruction. */ struct BranchPrediction { - /** Whether the branch will be isTaken. */ + /** Whether the branch will be taken. */ bool isTaken; /** The branch instruction's target address. If `isTaken = false`, the value diff --git a/src/include/simeng/config/yaml/ryml.hh b/src/include/simeng/config/yaml/ryml.hh index c35a4925f9..bed8f4620b 100644 --- a/src/include/simeng/config/yaml/ryml.hh +++ b/src/include/simeng/config/yaml/ryml.hh @@ -229,7 +229,7 @@ #define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch)) -/** A preprocessor foreach. Spectacular trick isTaken from: +/** A preprocessor foreach. Spectacular trick taken from: * http://stackoverflow.com/a/1872506/5875572 * The first argument is for a macro receiving a single argument, * which will be called with every subsequent argument. There is @@ -1449,7 +1449,7 @@ using std::index_sequence_for; /** C++11 implementation of integer sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template struct integer_sequence { @@ -1461,7 +1461,7 @@ struct integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence = integer_sequence; @@ -1544,19 +1544,19 @@ struct __make_integer_sequence /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using make_index_sequence = make_integer_sequence; /** C++11 implementation of index sequence * @see https://en.cppreference.com/w/cpp/utility/integer_sequence - * @see isTaken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ + * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ template using index_sequence_for = make_index_sequence; #endif @@ -4795,7 +4795,7 @@ namespace detail { /** @internal * @ingroup hash - * @see this was isTaken a great answer in stackoverflow: + * @see this was taken a great answer in stackoverflow: * https://stackoverflow.com/a/34597785/5875572 * @see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/ */ template @@ -12377,7 +12377,7 @@ inline size_t scan_one(csubstr str, const char *type_fmt, T *v) * * So we fake it by using a dynamic format with an explicit * field size set to the length of the given span. - * This trick is isTaken from: + * This trick is taken from: * https://stackoverflow.com/a/18368910/5875572 */ /* this is the actual format we'll use for scanning */ @@ -14624,7 +14624,7 @@ C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, substr buf, c namespace c4 { -//! isTaken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum +//! taken from http://stackoverflow.com/questions/15586163/c11-type-trait-to-differentiate-between-enum-class-and-regular-enum template using is_scoped_enum = std::integral_constant::value && !std::is_convertible::value>; @@ -15704,7 +15704,7 @@ template using cspanrs = spanrs; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- /** A non-owning span which always retains the capacity of the original - * range it was isTaken from (though it may loose its original size). + * range it was taken from (though it may loose its original size). * The resizing methods resize(), ltrim(), rtrim() as well * as the subselection methods subspan(), range(), first() and last() can be * used at will without loosing the original capacity; the full capacity span diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index 66433e05d2..e6420e998f 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -3,8 +3,8 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/Instruction.hh" +#include "simeng/branchPredictors/BranchPredictor.hh" #include "simeng/pipeline/PipelineBuffer.hh" namespace simeng { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 08cf1031bf..7a002bf8a0 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,6 +14,7 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc + branchPredictors/AlwaysNotTakenPredictor.cc branchPredictors/GenericPredictor.cc branchPredictors/PerceptronPredictor.cc config/ModelConfig.cc @@ -37,7 +38,6 @@ set(SIMENG_SOURCES pipeline/RenameUnit.cc pipeline/ReorderBuffer.cc pipeline/WritebackUnit.cc - branchPredictors/AlwaysNotTakenPredictor.cc ArchitecturalRegisterFileSet.cc CMakeLists.txt CoreInstance.cc diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index 1bf93c451f..e3b697433e 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -106,7 +106,7 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as isTaken, it will require a + // Instruction isn't a branch; if predicted as taken, it will require a // flush return {prediction_.isTaken, instructionAddress_ + 4}; } diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index 5eb1091c6b..c71b581a60 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -101,7 +101,7 @@ std::tuple Instruction::checkEarlyBranchMisprediction() const { "Early branch misprediction check shouldn't be called after execution"); if (!isBranch()) { - // Instruction isn't a branch; if predicted as isTaken, it will require a + // Instruction isn't a branch; if predicted as taken, it will require a // flush return {prediction_.isTaken, instructionAddress_ + 4}; } diff --git a/src/lib/branchPredictors/GenericPredictor.cc b/src/lib/branchPredictors/GenericPredictor.cc index 9092f73d52..dda9970c03 100644 --- a/src/lib/branchPredictors/GenericPredictor.cc +++ b/src/lib/branchPredictors/GenericPredictor.cc @@ -11,8 +11,8 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) globalHistoryLength_( config["Branch-Predictor"]["Global-History-Length"].as()), rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { - // Calculate the saturation counter boundary between weakly isTaken and - // not-isTaken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly isTaken state + // Calculate the saturation counter boundary between weakly taken and + // not-taken. `(2 ^ num_sat_cnt_bits) / 2` gives the weakly taken state // value uint8_t weaklyTaken = 1 << (satCntBits_ - 1); uint8_t satCntVal = (config["Branch-Predictor"]["Fallback-Static-Predictor"] @@ -143,8 +143,8 @@ void GenericPredictor::flush(uint64_t address) { void GenericPredictor::addToFTQ(uint64_t address, bool isTaken) { // Make the hashed index and add it to the FTQ - uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - - 1); + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); ftq_.emplace_back(isTaken, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 706261edc1..32bbe9d7c8 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -203,10 +203,10 @@ void FetchUnit::tick() { bufferedBytes_ -= bytesRead; if (!prediction.isTaken) { - // Predicted as not isTaken; increment PC to next instruction + // Predicted as not taken; increment PC to next instruction pc_ += bytesRead; } else { - // Predicted as isTaken; set PC to predicted target address + // Predicted as taken; set PC to predicted target address pc_ = prediction.target; } diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 00279300b8..92b8e9393a 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -493,7 +493,7 @@ TEST_F(AArch64InstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch isTaken) is handled correctly +// Test that a correct prediction (branch taken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -510,7 +510,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is isTaken is handled correctly + // Test a correct prediction where branch is taken is handled correctly pred = {true, 80 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -522,7 +522,7 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not isTaken) is handled correctly +// Test that a correct prediction (branch not taken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_notTaken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -539,7 +539,7 @@ TEST_F(AArch64InstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't isTaken is handled correctly + // Test a correct prediction where a branch isn't taken is handled correctly pred = {false, 80 + 4}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -580,7 +580,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 100 + 0x28); } -// Test that an incorrect prediction (wrong isTaken) is handled correctly +// Test that an incorrect prediction (wrong taken) is handled correctly TEST_F(AArch64InstructionTest, incorrectPred_taken) { // insn is `cbz x2, #0x28` Instruction insn = Instruction(arch, *cbzMetadata.get(), MicroOpInfo()); @@ -597,7 +597,7 @@ TEST_F(AArch64InstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - isTaken is wrong + // Test an incorrect prediction is handled correctly - taken is wrong pred = {true, 100 + 0x28}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index a9b8c07084..8ecdc7d88b 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -232,7 +232,7 @@ TEST_P(PipelineFetchUnitTest, halted) { EXPECT_TRUE(fetchUnit.hasHalted()); } -// Tests that fetching a branch instruction (predicted isTaken) mid block causes a +// Tests that fetching a branch instruction (predicted taken) mid block causes a // branch stall + discards the remaining fetched instructions TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { const uint8_t pc = 16; @@ -266,7 +266,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); fetchUnit.tick(); - // For second tick, process a isTaken branch meaning rest of block is discarded + // For second tick, process a taken branch meaning rest of block is discarded // & a new memory block is requested EXPECT_CALL(memory, getCompletedReads()).Times(0); EXPECT_CALL(memory, clearCompletedReads()).Times(1); @@ -388,7 +388,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { } // Tests the functionality of idling the supply to the Loop Buffer one of not -// isTaken branch at the loopBoundaryAddress_ +// taken branch at the loopBoundaryAddress_ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set instructions to be fetched from memory memory::MemoryReadResult memReadResultA = { @@ -432,7 +432,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); - // Attempt to fill Loop Buffer but prevent it on a not isTaken outcome at the + // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the // loopBoundaryAddress_ branch // Tick 4 times to process all 16 bytes of fetched data for (int i = 0; i < 4; i++) { diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index c40b503a6c..6103cd4f5c 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -467,7 +467,7 @@ TEST_F(RiscVInstructionTest, earlyBranchMisprediction) { EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); } -// Test that a correct prediction (branch isTaken) is handled correctly +// Test that a correct prediction (branch taken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -484,7 +484,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where branch is isTaken is handled correctly + // Test a correct prediction where branch is taken is handled correctly pred = {true, 400 - 86}; insn.setBranchPrediction(pred); matchingPred = (insn.getBranchPrediction() == pred); @@ -497,7 +497,7 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), pred.target); } -// Test that a correct prediction (branch not isTaken) is handled correctly +// Test that a correct prediction (branch not taken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_notTaken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -514,7 +514,7 @@ TEST_F(RiscVInstructionTest, correctPred_notTaken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test a correct prediction where a branch isn't isTaken is handled correctly + // Test a correct prediction where a branch isn't taken is handled correctly // imm operand 0x28 has 4 added implicitly by dissassembler pred = {false, 400 + 4}; insn.setBranchPrediction(pred); @@ -559,7 +559,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 400 - 86); } -// Test that an incorrect prediction (wrong isTaken) is handled correctly +// Test that an incorrect prediction (wrong taken) is handled correctly TEST_F(RiscVInstructionTest, incorrectPred_taken) { // insn is `bgeu a5, a4, -86` Instruction insn = Instruction(arch, *bgeuMetadata.get()); @@ -576,7 +576,7 @@ TEST_F(RiscVInstructionTest, incorrectPred_taken) { std::tuple tup = {false, 0}; EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - // Test an incorrect prediction is handled correctly - isTaken is wrong + // Test an incorrect prediction is handled correctly - taken is wrong // imm operand 0x28 has 4 added implicitly by dissassembler pred = {true, 400 - 86}; insn.setBranchPrediction(pred); From fc779bb505a0d9102ba01c25ce0da11ec08bb312 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:08:09 +0100 Subject: [PATCH 127/191] rebase --- src/include/simeng/CoreInstance.hh | 6 +- src/include/simeng/Instruction.hh | 2 +- src/include/simeng/arch/Architecture.hh | 2 +- .../simeng/arch/aarch64/Instruction.hh | 2 +- src/include/simeng/arch/riscv/Instruction.hh | 2 +- .../AlwaysNotTakenPredictor.hh | 5 +- .../BranchPredictor.hh | 14 +-- .../GenericPredictor.hh | 31 +++-- .../PerceptronPredictor.hh | 38 ++++--- src/include/simeng/pipeline/ExecuteUnit.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 2 +- src/lib/CMakeLists.txt | 6 +- .../AlwaysNotTakenPredictor.cc | 2 +- .../GenericPredictor.cc | 33 +++--- .../PerceptronPredictor.cc | 58 ++++++---- src/lib/pipeline/FetchUnit.cc | 5 +- test/regression/RegressionTest.cc | 4 +- test/unit/GenericPredictorTest.cc | 106 +++++++++--------- test/unit/MockBranchPredictor.hh | 8 +- test/unit/PerceptronPredictorTest.cc | 106 +++++++++--------- test/unit/pipeline/FetchUnitTest.cc | 11 +- 21 files changed, 249 insertions(+), 196 deletions(-) rename src/include/simeng/{branchPredictors => branchpredictors}/AlwaysNotTakenPredictor.hh (80%) rename src/include/simeng/{branchPredictors => branchpredictors}/BranchPredictor.hh (81%) rename src/include/simeng/{branchPredictors => branchpredictors}/GenericPredictor.hh (70%) rename src/include/simeng/{branchPredictors => branchpredictors}/PerceptronPredictor.hh (69%) rename src/lib/{branchPredictors => branchpredictors}/AlwaysNotTakenPredictor.cc (86%) rename src/lib/{branchPredictors => branchpredictors}/GenericPredictor.cc (85%) rename src/lib/{branchPredictors => branchpredictors}/PerceptronPredictor.cc (76%) diff --git a/src/include/simeng/CoreInstance.hh b/src/include/simeng/CoreInstance.hh index b66519bf64..64e2f9e1f5 100644 --- a/src/include/simeng/CoreInstance.hh +++ b/src/include/simeng/CoreInstance.hh @@ -8,9 +8,9 @@ #include "simeng/arch/Architecture.hh" #include "simeng/arch/aarch64/Architecture.hh" #include "simeng/arch/riscv/Architecture.hh" -#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" -#include "simeng/branchPredictors/GenericPredictor.hh" -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/AlwaysNotTakenPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/FixedLatencyMemoryInterface.hh" diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index c28f2177c3..6385995a7b 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -5,7 +5,7 @@ #include "capstone/capstone.h" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/memory/MemoryInterface.hh" #include "simeng/span.hh" diff --git a/src/include/simeng/arch/Architecture.hh b/src/include/simeng/arch/Architecture.hh index 1a28a0bd08..aa293d6f5f 100644 --- a/src/include/simeng/arch/Architecture.hh +++ b/src/include/simeng/arch/Architecture.hh @@ -6,7 +6,7 @@ #include "simeng/Core.hh" #include "simeng/Instruction.hh" #include "simeng/arch/ProcessStateChange.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/kernel/Linux.hh" #include "simeng/memory/MemoryInterface.hh" diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index 7bf9341ded..76e74d7eb7 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -6,7 +6,7 @@ #include "simeng/Instruction.hh" #include "simeng/arch/aarch64/InstructionGroups.hh" #include "simeng/arch/aarch64/operandContainer.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" struct cs_arm64_op; diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index 69257153d8..9e707449c6 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -7,7 +7,7 @@ #include "simeng/Instruction.hh" #include "simeng/arch/riscv/InstructionGroups.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { namespace arch { diff --git a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh similarity index 80% rename from src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh rename to src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index b43c361e54..aad7aa67a3 100644 --- a/src/include/simeng/branchPredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -1,6 +1,6 @@ #pragma once -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { @@ -12,7 +12,8 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) override; + int64_t knownOffset, + bool getPrediction = true) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ diff --git a/src/include/simeng/branchPredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh similarity index 81% rename from src/include/simeng/branchPredictors/BranchPredictor.hh rename to src/include/simeng/branchpredictors/BranchPredictor.hh index 2bcf76eb25..8f7b568934 100644 --- a/src/include/simeng/branchPredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -47,9 +47,13 @@ class BranchPredictor { virtual ~BranchPredictor(){}; /** Generate a branch prediction for the specified instruction address with a - * branch type and possible known branch offset. */ - virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) = 0; + * branch type and possible known branch offset. There is and optional + * boolean argument for if no prediction is needed from the branch + * predictor (e.g., in the event that the fetch unit has identified this + * branch as being a part of a queue and so reusing a previous prediction).*/ + virtual BranchPrediction predict( + uint64_t address, BranchType type, int64_t knownOffset, + bool getPrediction = true) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program @@ -63,10 +67,6 @@ class BranchPredictor { * once, the exact order that the individual instructions within this block * are flushed does not matter so long as they are all flushed) */ virtual void flush(uint64_t address) = 0; - - /** Adds instruction to the Fetch Target Queue without making a new prediction - */ - virtual void addToFTQ(uint64_t address, bool isTaken) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchPredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh similarity index 70% rename from src/include/simeng/branchPredictors/GenericPredictor.hh rename to src/include/simeng/branchpredictors/GenericPredictor.hh index a288583746..f30d213dbb 100644 --- a/src/include/simeng/branchPredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { @@ -28,22 +28,28 @@ class GenericPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ + * known. Returns a branch direction and branch target address. Optional + * arguments of getPrediction and pastDirection for use in the event that a + * new prediction is not required from the BP for a branch (e.g., if the + * fetch unit has identified the branch as being a part of a loop and so is + * reusing a previous prediction). If no prediction is required, then the + * direction prediction that is being used in lieu of a new prediction must + * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) override; + int64_t knownOffset = 0, + bool getPrediction = true) override; - /** Updates appropriate predictor model objects based on the address and - * outcome of the branch instruction. */ + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on branches in + * program order. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Provides RAS rewinding behaviour. */ + /** Flushes the most recently predicted branch from the BP. Address is + * required to ensure that only the correct branch is removed from the RAS. + * */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction - */ - void addToFTQ(uint64_t address, bool isTaken) override; - private: /** The bitlength of the BTB index; BTB will have 2^bits entries. */ uint8_t btbBits_; @@ -56,6 +62,11 @@ class GenericPredictor : public BranchPredictor { * history state of branches that are currently unresolved */ std::deque> ftq_; + /** Keep the last ftq entry as a separate variable to be reused for loops + * in the event that the ftq_ is empty by the time the next predict() is + * called */ + std::pair lastFtqEntry_; + /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/branchPredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh similarity index 69% rename from src/include/simeng/branchPredictors/PerceptronPredictor.hh rename to src/include/simeng/branchpredictors/PerceptronPredictor.hh index c846d045cf..2d31690fa5 100644 --- a/src/include/simeng/branchPredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/config/SimInfo.hh" namespace simeng { @@ -31,22 +31,28 @@ class PerceptronPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ + * known. Returns a branch direction and branch target address. Optional + * arguments of getPrediction and pastDirection for use in the event that a + * new prediction is not required from the BP for a branch (e.g., if the + * fetch unit has identified the branch as being a part of a loop and so is + * reusing a previous prediction). If no prediction is required, then the + * direction prediction that is being used in lieu of a new prediction must + * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) override; + int64_t knownOffset = 0, + bool getPrediction = true) override; - /** Updates appropriate predictor model objects based on the address and - * outcome of the branch instruction. */ + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on branches in + * program order. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Provides RAS rewinding behaviour. */ + /** Flushes the most recently predicted branch from the BP. Address is + * required to ensure that only the correct branch is removed from the RAS. + * */ void flush(uint64_t address) override; - /** Adds instruction to the Fetch Target Queue without making a new prediction - */ - void addToFTQ(uint64_t address, bool isTaken) override; - private: /** Returns the dot product of a perceptron and a history vector. Used to * determine a direction prediction */ @@ -63,9 +69,15 @@ class PerceptronPredictor : public BranchPredictor { * in Jiminez and Lin */ std::vector, uint64_t>> btb_; - /** Fetch Target Queue containing the direction prediction and previous global - * history state of branches that are currently unresolved */ - std::deque> ftq_; + /** Fetch Target Queue containing the dot product of the perceptron and the + * global history; and the global history, both at the time of prediction, + * for each of the branches that are currently unresolved. */ + std::deque> ftq_; + + /** Keep the last ftq entry as a separate variable to be reused for loops + * in the event that the ftq_ is empty by the time the next predict() is + * called */ + std::pair lastFtqEntry_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. Each bit represents a branch taken (1) or not diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index e6420e998f..450ad4b384 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -4,7 +4,7 @@ #include #include "simeng/Instruction.hh" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/pipeline/PipelineBuffer.hh" namespace simeng { diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index 2799d54fa9..b6459935ed 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,7 +4,7 @@ #include #include -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { namespace pipeline { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 7a002bf8a0..ac393b19c2 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,9 +14,9 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc - branchPredictors/AlwaysNotTakenPredictor.cc - branchPredictors/GenericPredictor.cc - branchPredictors/PerceptronPredictor.cc + branchpredictors/AlwaysNotTakenPredictor.cc + branchpredictors/GenericPredictor.cc + branchpredictors/PerceptronPredictor.cc config/ModelConfig.cc kernel/Linux.cc kernel/LinuxProcess.cc diff --git a/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc similarity index 86% rename from src/lib/branchPredictors/AlwaysNotTakenPredictor.cc rename to src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index d3f910283b..847e32740e 100644 --- a/src/lib/branchPredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/branchPredictors/AlwaysNotTakenPredictor.hh" +#include "simeng/branchpredictors/AlwaysNotTakenPredictor.hh" namespace simeng { diff --git a/src/lib/branchPredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc similarity index 85% rename from src/lib/branchPredictors/GenericPredictor.cc rename to src/lib/branchpredictors/GenericPredictor.cc index dda9970c03..75a0c9a685 100644 --- a/src/lib/branchPredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" #include @@ -27,6 +27,10 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // outcomes are stored to allow rolling back the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + + // Set dummy lastFtqEntry value, needed to ensure that non-prediction + // getting predict() calls in tests work. + lastFtqEntry_ = {true, 0}; } GenericPredictor::~GenericPredictor() { @@ -36,8 +40,9 @@ GenericPredictor::~GenericPredictor() { ftq_.clear(); } -BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset) { +BranchPrediction GenericPredictor::predict( + uint64_t address, BranchType type, int64_t knownOffset, + bool getPrediction) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -45,6 +50,17 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + // If a branch prediction is not required, then we can avoid a lot of the + // logic, and just determine the direction, and add the branch to the ftq + if (!getPrediction) { + // Add branch to the back of the ftq + ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); + // Speculatively update the global history + globalHistory_ = ((globalHistory_ << 1) | lastFtqEntry_.first) & + globalHistoryMask_; + return {false, 0}; + } + // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = @@ -78,6 +94,7 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Store the hashed index for correct hashing in update() ftq_.emplace_back(prediction.isTaken, hashedIndex); + lastFtqEntry_ = {prediction.isTaken, hashedIndex}; // Speculatively update the global history globalHistory_ = @@ -140,14 +157,4 @@ void GenericPredictor::flush(uint64_t address) { // Roll back global history globalHistory_ >>= 1; } - -void GenericPredictor::addToFTQ(uint64_t address, bool isTaken) { - // Make the hashed index and add it to the FTQ - uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - ftq_.emplace_back(isTaken, hashedIndex); - // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; -} - } // namespace simeng diff --git a/src/lib/branchPredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc similarity index 76% rename from src/lib/branchPredictors/PerceptronPredictor.cc rename to src/lib/branchpredictors/PerceptronPredictor.cc index 8336d62772..550cb74b87 100644 --- a/src/lib/branchPredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -1,4 +1,4 @@ -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" namespace simeng { @@ -22,6 +22,10 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + + // Set dummy lastFtqEntry value, needed to ensure that non-prediction + // getting predict() calls in tests work. + lastFtqEntry_ = {1, 0}; } PerceptronPredictor::~PerceptronPredictor() { @@ -31,7 +35,24 @@ PerceptronPredictor::~PerceptronPredictor() { } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset) { + int64_t knownOffset, + bool getPrediction) { + // If no prediction required, add branch to ftq and return dummy + // prediction, which will not be used by the fetch unit + if (!getPrediction) { + // Add branch to the ftq using the past dot product in lieu of a new + // prediction. Because the loop buffer only supplies if there have been + // no branch instructions since the branch defining the loop, we know + // that the past dot product is the one most recently added to the ftq_ + ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); + // Update global history + globalHistory_ = + ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & + globalHistoryMask_; + // Return dummy prediction + return {false, 0}; + } + // Get the hashed index for the prediction table. XOR the global history with // the non-zero bits of the address, and then keep only the btbBits_ bits of // the output to keep it in bounds of the prediction table. @@ -48,7 +69,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Determine direction prediction based on its sign bool direction = (Pout >= 0); - // Retrieve target prediction + // If there is a known offset then calculate target accordingly, otherwise + // retrieve the target prediction from the btb. uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; @@ -79,12 +101,14 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, if (!prediction.isTaken) prediction.target = address + 4; } - // Store the global history for correct hashing in update() -- + // Store the Pout and global history for correct update() -- // needs to be global history and not the hashed index as hashing loses - // information at longer global history lengths - ftq_.emplace_back(prediction.isTaken, globalHistory_); + // information and the global history is required for updating perceptrons. + ftq_.emplace_back(Pout, globalHistory_); + lastFtqEntry_ = {Pout, globalHistory_}; - // speculatively update global history + // Speculatively update the global history based on the direction + // prediction being made globalHistory_ = ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; @@ -93,8 +117,9 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) { - // Get previous branch state and prediction from FTQ - bool prevPrediction = ftq_.front().first; + // Retrieve the previous global history and branch direction prediction from + // the front of the ftq (assumes branches are updated in program order). + int64_t prevPout = ftq_.front().first; uint64_t prevGlobalHistory = ftq_.front().second; ftq_.pop_front(); @@ -102,15 +127,16 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); + std::vector perceptron = btb_[hashedIndex].first; // Work out the most recent prediction - int64_t Pout = getDotProduct(perceptron, prevGlobalHistory); - bool directionPrediction = (Pout >= 0); + bool directionPrediction = (prevPout >= 0); // Update the perceptron if the prediction was wrong, or the dot product's // magnitude was not greater than the training threshold - if ((directionPrediction != isTaken) || (abs(Pout) < trainingThreshold_)) { + if ((directionPrediction != isTaken) || + (abs(prevPout) < trainingThreshold_)) { int8_t t = (isTaken) ? 1 : -1; if ((directionPrediction != taken) || (static_cast(std::abs(Pout)) < trainingThreshold_)) { @@ -137,7 +163,7 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (prevPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); + if (directionPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -168,12 +194,6 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -void PerceptronPredictor::addToFTQ(uint64_t address, bool isTaken) { - // Add instruction to the FTQ in event of reused prediction - ftq_.emplace_back(isTaken, globalHistory_); - globalHistory_ = ((globalHistory_ << 1) | isTaken) & globalHistoryMask_; -} - int64_t PerceptronPredictor::getDotProduct( const std::vector& perceptron, uint64_t history) { int64_t Pout = perceptron[globalHistoryLength_]; diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 32bbe9d7c8..46318bda69 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -55,8 +55,9 @@ void FetchUnit::tick() { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Let the branch predictor know the prediction is being reused so that // the FTQ can be kept up to date - branchPredictor_.addToFTQ(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchPrediction().isTaken); + branchPredictor_.predict(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset(), false); branchesExecuted_++; } diff --git a/test/regression/RegressionTest.cc b/test/regression/RegressionTest.cc index d1502344b1..237b0518a3 100644 --- a/test/regression/RegressionTest.cc +++ b/test/regression/RegressionTest.cc @@ -2,8 +2,8 @@ #include -#include "simeng/branchPredictors/GenericPredictor.hh" -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" #include "simeng/config/SimInfo.hh" #include "simeng/kernel/Linux.hh" #include "simeng/kernel/LinuxProcess.hh" diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index b24fbee3ff..945a767154 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/branchPredictors/GenericPredictor.hh" +#include "simeng/branchpredictors/GenericPredictor.hh" namespace simeng { @@ -111,25 +111,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -139,25 +139,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -167,25 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -195,25 +195,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 16, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -268,17 +268,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -288,17 +288,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index f09444165d..56777c0846 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -1,19 +1,19 @@ #pragma once #include "gmock/gmock.h" -#include "simeng/branchPredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" namespace simeng { /** Mock implementation of the `BranchPredictor` interface. */ class MockBranchPredictor : public BranchPredictor { public: - MOCK_METHOD3(predict, BranchPrediction(uint64_t address, BranchType type, - int64_t knownTarget)); + MOCK_METHOD4(predict, + BranchPrediction(uint64_t address, BranchType type, + int64_t knownTarget, bool getPrediction)); MOCK_METHOD4(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type)); MOCK_METHOD1(flush, void(uint64_t address)); - MOCK_METHOD2(addToFTQ, void(uint64_t address, bool taken)); }; } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 40a36882b7..5dca2bcffe 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -1,6 +1,6 @@ #include "MockInstruction.hh" #include "gtest/gtest.h" -#include "simeng/branchPredictors/PerceptronPredictor.hh" +#include "simeng/branchpredictors/PerceptronPredictor.hh" namespace simeng { @@ -99,25 +99,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -127,25 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -155,25 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -183,25 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -254,17 +254,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, true); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -276,17 +276,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); - predictor.addToFTQ(0, false); + predictor.predict(0, BranchType::Conditional, 0, false); predictor.update(0, true, 4, BranchType::Conditional); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 8ecdc7d88b..ae6311f112 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -94,7 +94,7 @@ TEST_P(PipelineFetchUnitTest, TickStalled) { EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_, _, _)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _, _)).Times(0); fetchUnit.tick(); @@ -279,7 +279,8 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff)).WillOnce(Return(pred)); + EXPECT_CALL(predictor, predict(20, bType, knownOff, true)).WillOnce + (Return(pred)); fetchUnit.tick(); // Ensure on next tick, predecode is not called @@ -325,7 +326,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { // Set the expectation from the predictor to be true so a loop body will // be detected - ON_CALL(predictor, predict(_, _, _)) + ON_CALL(predictor, predict(_, _, _, _)) .WillByDefault(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -417,7 +418,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set the first expectation from the predictor to be true so a loop body will // be detected - EXPECT_CALL(predictor, predict(_, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, _)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -429,7 +430,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the From d2016c656d3cdf1c53637f5f70a5b5b2cc51834e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:08:45 +0100 Subject: [PATCH 128/191] rebase --- .../simeng/branchpredictors/AlwaysNotTakenPredictor.hh | 2 +- src/include/simeng/branchpredictors/BranchPredictor.hh | 2 +- src/include/simeng/branchpredictors/GenericPredictor.hh | 2 +- src/include/simeng/branchpredictors/PerceptronPredictor.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 4 ++-- src/lib/branchpredictors/PerceptronPredictor.cc | 4 ++-- src/lib/pipeline/FetchUnit.cc | 2 +- test/unit/pipeline/FetchUnitTest.cc | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index aad7aa67a3..e366488d23 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -13,7 +13,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction = true) override; + bool isLoop = false) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 8f7b568934..197f57263e 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -53,7 +53,7 @@ class BranchPredictor { * branch as being a part of a queue and so reusing a previous prediction).*/ virtual BranchPrediction predict( uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction = true) = 0; + bool isLoop = false) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index f30d213dbb..4b16aad1c8 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -37,7 +37,7 @@ class GenericPredictor : public BranchPredictor { * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, - bool getPrediction = true) override; + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 2d31690fa5..091f5261b0 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -40,7 +40,7 @@ class PerceptronPredictor : public BranchPredictor { * be provided as an argument to predict. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, - bool getPrediction = true) override; + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 75a0c9a685..f4f5d0548b 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -42,7 +42,7 @@ GenericPredictor::~GenericPredictor() { BranchPrediction GenericPredictor::predict( uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction) { + bool isLoop) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -52,7 +52,7 @@ BranchPrediction GenericPredictor::predict( // If a branch prediction is not required, then we can avoid a lot of the // logic, and just determine the direction, and add the branch to the ftq - if (!getPrediction) { + if (isLoop) { // Add branch to the back of the ftq ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); // Speculatively update the global history diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 550cb74b87..69fc803c40 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -36,10 +36,10 @@ PerceptronPredictor::~PerceptronPredictor() { BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset, - bool getPrediction) { + bool isLoop) { // If no prediction required, add branch to ftq and return dummy // prediction, which will not be used by the fetch unit - if (!getPrediction) { + if (isLoop) { // Add branch to the ftq using the past dot product in lieu of a new // prediction. Because the loop buffer only supplies if there have been // no branch instructions since the branch defining the loop, we know diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 46318bda69..2d9709bbe7 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -57,7 +57,7 @@ void FetchUnit::tick() { // the FTQ can be kept up to date branchPredictor_.predict(macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset(), false); + macroOp[0]->getKnownOffset(), true); branchesExecuted_++; } diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index ae6311f112..79092d2e5e 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -279,7 +279,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff, true)).WillOnce + EXPECT_CALL(predictor, predict(20, bType, knownOff, false)).WillOnce (Return(pred)); fetchUnit.tick(); From 59224ce95061cd943abc67329d49100cac6e07cf Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 12:16:10 +0100 Subject: [PATCH 129/191] Updating BP tests for consistency with new predict() arguments --- .../AlwaysNotTakenPredictor.hh | 3 +- test/unit/GenericPredictorTest.cc | 104 +++++++++--------- test/unit/PerceptronPredictorTest.cc | 104 +++++++++--------- 3 files changed, 105 insertions(+), 106 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index e366488d23..d057027db5 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -5,8 +5,7 @@ namespace simeng { /** An "Always Not Taken" branch predictor; predicts all branches as not - * taken. - */ + * taken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: /** Generate a branch prediction for the specified instruction address; will diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 945a767154..0c698cd276 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -111,25 +111,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -139,25 +139,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -167,25 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -195,25 +195,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 16, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 16, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -268,17 +268,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -288,17 +288,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 5dca2bcffe..15d6c88250 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -99,25 +99,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -127,25 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -155,25 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -183,25 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, false, 4, BranchType::Conditional); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -254,17 +254,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -276,17 +276,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); - predictor.predict(0, BranchType::Conditional, 0, false); + predictor.predict(0, BranchType::Conditional, 0, true); predictor.update(0, true, 4, BranchType::Conditional); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); From 3994c45809c535fa1f036a49b962aa0435953e93 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 12:32:16 +0100 Subject: [PATCH 130/191] Updating docs --- docs/sphinx/developer/components/branchPred.rst | 8 ++++---- src/include/simeng/arch/aarch64/helpers/conditional.hh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 63cdc8d899..767fd1bead 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -3,9 +3,9 @@ Branch prediction SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredictor`` class to enable speculative execution. -Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, ``flush``, and ``addToFTQ``` functions. ``predict`` provides a branch prediction, both target and direction, ``update`` updates an instructions' prediction, ``flush`` provides optional algorithm specific flushing functionality, and ``addToFTQ`` adds an instruction to the predictor's Fetch Target Queue (FTQ) when a new prediction is not needed. +Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, for a branch instruction. ``update`` updates the branch predictor's prediction mechanism on the actual outcome of a branch. ``flush`` provides algorithm specific flushing functionality. -The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: +The ``predict`` function is passed an instruction address, branch type, a possible known target, and optionally whether the branch is in a loop. The branch type argument currently supports the following types: - ``Conditional`` - ``LoopClosing`` @@ -13,11 +13,11 @@ The ``predict`` function is passed an instruction address, branch type, and a po - ``SubroutineCall`` - ``Unconditional`` -The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. +The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. If the branch is a part of a loop, then only a dummy branch prediction is returned by ``predict``, as the fetch unit will reuse a previous branch prediction and so no new branch prediction is needed. The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the front of the ftq on ``predict`` and ``addToFTQ``, and a single entry is removed from the back of the queue on ``update`` and from the front of the queue on ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the back of the ftq on ``predict``, and a single entry is removed from the front of the queue on ``update`` and from the back of the queue on ``flush``. Generic Predictor ----------------- diff --git a/src/include/simeng/arch/aarch64/helpers/conditional.hh b/src/include/simeng/arch/aarch64/helpers/conditional.hh index 2b3ea1b9c3..e541eb276a 100644 --- a/src/include/simeng/arch/aarch64/helpers/conditional.hh +++ b/src/include/simeng/arch/aarch64/helpers/conditional.hh @@ -56,7 +56,7 @@ uint8_t ccmp_reg(srcValContainer& sourceValues, /** Helper function for instructions with the format `cb rn, #imm`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch isTaken, uint64_t address]. */ + * Returns tuple of type [bool branch taken, uint64_t address]. */ template std::tuple condBranch_cmpToZero( srcValContainer& sourceValues, @@ -91,7 +91,7 @@ T cs_4ops(srcValContainer& sourceValues, /** Helper function for instructions with the format `tb rn, #imm, * label`. * T represents the type of sourceValues (e.g. for xn, T = uint64_t). - * Returns tuple of type [bool branch isTaken, uint64_t address]. */ + * Returns tuple of type [bool branch taken, uint64_t address]. */ template std::tuple tbnz_tbz( srcValContainer& sourceValues, From d4579a08f52c2d59286512aa4401f58d0d8e314b Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 12:52:32 +0100 Subject: [PATCH 131/191] Updating comments --- .../simeng/branchpredictors/BranchPredictor.hh | 12 ++++++------ .../simeng/branchpredictors/GenericPredictor.hh | 13 ++++++------- .../simeng/branchpredictors/PerceptronPredictor.hh | 13 ++++++------- src/include/simeng/pipeline/FetchUnit.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 4 ++++ src/lib/branchpredictors/GenericPredictor.cc | 9 +++++---- src/lib/branchpredictors/PerceptronPredictor.cc | 10 +++++----- src/lib/pipeline/FetchUnit.cc | 6 +++--- 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 197f57263e..da6d486de7 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -47,17 +47,17 @@ class BranchPredictor { virtual ~BranchPredictor(){}; /** Generate a branch prediction for the specified instruction address with a - * branch type and possible known branch offset. There is and optional - * boolean argument for if no prediction is needed from the branch - * predictor (e.g., in the event that the fetch unit has identified this - * branch as being a part of a queue and so reusing a previous prediction).*/ + * branch type and possible known branch offset. There is an optional + * boolean argument for if the branch is a part of a loop, in which case + * the fetch unit does not require a new prediction and so only a dummy + * prediction is returned. */ virtual BranchPrediction predict( uint64_t address, BranchType type, int64_t knownOffset, bool isLoop = false) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program - * order */ + * order. */ virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) = 0; @@ -65,7 +65,7 @@ class BranchPredictor { * via the instruction address. Branches must be flushed in reverse * program order (though, if a block of n instructions is being flushed at * once, the exact order that the individual instructions within this block - * are flushed does not matter so long as they are all flushed) */ + * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; }; diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 4b16aad1c8..f029bbc7c7 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -28,13 +28,12 @@ class GenericPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. Optional - * arguments of getPrediction and pastDirection for use in the event that a - * new prediction is not required from the BP for a branch (e.g., if the - * fetch unit has identified the branch as being a part of a loop and so is - * reusing a previous prediction). If no prediction is required, then the - * direction prediction that is being used in lieu of a new prediction must - * be provided as an argument to predict. */ + * known. Returns a branch direction and branch target address. There is + * also an optional boolean argument for whether or not the branch has + * been identified as being a part of a loop. If the branch is a loop + * branch, then the fetch unit will reuse a previous prediction and so no + * new prediction is required. Therefore, predict() returns only a dummy + * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, bool isLoop = false) override; diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 091f5261b0..efa96ef519 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -31,13 +31,12 @@ class PerceptronPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. Optional - * arguments of getPrediction and pastDirection for use in the event that a - * new prediction is not required from the BP for a branch (e.g., if the - * fetch unit has identified the branch as being a part of a loop and so is - * reusing a previous prediction). If no prediction is required, then the - * direction prediction that is being used in lieu of a new prediction must - * be provided as an argument to predict. */ + * known. Returns a branch direction and branch target address. There is + * also an optional boolean argument for whether or not the branch has + * been identified as being a part of a loop. If the branch is a loop + * branch, then the fetch unit will reuse a previous prediction and so no + * new prediction is required. Therefore, predict() returns only a dummy + * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset = 0, bool isLoop = false) override; diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index c5a7383b4f..035942caac 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -122,7 +122,7 @@ class FetchUnit { uint16_t bufferedBytes_ = 0; /** The number of branch instructions that were executed. */ - uint64_t branchesExecuted_ = 0; + uint64_t branchesFetched_ = 0; /** Let the following PipelineFetchUnitTest derived classes be a friend of * this class to allow proper testing of 'tick' function. */ diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index b6459935ed..342355eaf2 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -75,6 +75,8 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } + /** flush branches in the buffer from the branch predictor, where the + * buffer contains microops */ void flushBranchMicroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& uop = getTailSlots()[slot]; @@ -88,6 +90,8 @@ class PipelineBuffer { } } + /** flush branches in the buffer from the branch predictor, where the + * buffer contains macroops */ void flushBranchMacroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& macroOp = getTailSlots()[slot]; diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index f4f5d0548b..d09408d136 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -28,8 +28,8 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - // Set dummy lastFtqEntry value, needed to ensure that non-prediction - // getting predict() calls in tests work. + // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() + // calls in tests work. lastFtqEntry_ = {true, 0}; } @@ -50,14 +50,15 @@ BranchPrediction GenericPredictor::predict( uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - // If a branch prediction is not required, then we can avoid a lot of the - // logic, and just determine the direction, and add the branch to the ftq + // If branch is in a loop then a new prediction is not required. Just need + // to update ftq and global history if (isLoop) { // Add branch to the back of the ftq ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); // Speculatively update the global history globalHistory_ = ((globalHistory_ << 1) | lastFtqEntry_.first) & globalHistoryMask_; + // prediction not required so return dummy prediction return {false, 0}; } diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 69fc803c40..1f5a62d229 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -23,8 +23,8 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - // Set dummy lastFtqEntry value, needed to ensure that non-prediction - // getting predict() calls in tests work. + // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() + // calls in tests work. lastFtqEntry_ = {1, 0}; } @@ -37,11 +37,11 @@ PerceptronPredictor::~PerceptronPredictor() { BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop) { - // If no prediction required, add branch to ftq and return dummy - // prediction, which will not be used by the fetch unit + // If branch is in a loop then a new prediction is not required. Just need + // to update ftq and global history if (isLoop) { // Add branch to the ftq using the past dot product in lieu of a new - // prediction. Because the loop buffer only supplies if there have been + // prediction. Because the loop buffer supplies only if there have been // no branch instructions since the branch defining the loop, we know // that the past dot product is the one most recently added to the ftq_ ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 2d9709bbe7..f52d6f1599 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -58,7 +58,7 @@ void FetchUnit::tick() { branchPredictor_.predict(macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset(), true); - branchesExecuted_++; + branchesFetched_++; } // Cycle queue by moving front entry to back @@ -153,7 +153,7 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { prediction = branchPredictor_.predict(pc_, macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); - branchesExecuted_++; + branchesFetched_++; macroOp[0]->setBranchPrediction(prediction); } @@ -287,7 +287,7 @@ void FetchUnit::flushLoopBuffer() { loopBoundaryAddress_ = 0; } -uint64_t FetchUnit::getBranchFetchedCount() const { return branchesExecuted_; } +uint64_t FetchUnit::getBranchFetchedCount() const { return branchesFetched_; } } // namespace pipeline } // namespace simeng From 1373773ee287e1d3a9e08002ed81317cfa94a2e6 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:09:03 +0100 Subject: [PATCH 132/191] rebase --- .../simeng/branchpredictors/AlwaysNotTakenPredictor.hh | 3 +-- src/include/simeng/branchpredictors/BranchPredictor.hh | 6 +++--- src/include/simeng/branchpredictors/GenericPredictor.hh | 4 ++-- .../simeng/branchpredictors/PerceptronPredictor.hh | 6 +++--- src/lib/branchpredictors/GenericPredictor.cc | 9 ++++----- src/lib/branchpredictors/PerceptronPredictor.cc | 6 ++---- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index d057027db5..cbab63f0c3 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -11,8 +11,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset, - bool isLoop = false) override; + int64_t knownOffset, bool isLoop = false) override; /** Provide branch results to update the prediction model for the specified * instruction address. As this model is static, this does nothing. */ diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index da6d486de7..fe5aa077b9 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -51,9 +51,9 @@ class BranchPredictor { * boolean argument for if the branch is a part of a loop, in which case * the fetch unit does not require a new prediction and so only a dummy * prediction is returned. */ - virtual BranchPrediction predict( - uint64_t address, BranchType type, int64_t knownOffset, - bool isLoop = false) = 0; + virtual BranchPrediction predict(uint64_t address, BranchType type, + int64_t knownOffset, + bool isLoop = false) = 0; /** Provide branch results to update the prediction model for the specified * instruction address. Update must be called on instructions in program diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index f029bbc7c7..db46df59b7 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -35,8 +35,8 @@ class GenericPredictor : public BranchPredictor { * new prediction is required. Therefore, predict() returns only a dummy * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0, + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index efa96ef519..b9b147e579 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -38,8 +38,8 @@ class PerceptronPredictor : public BranchPredictor { * new prediction is required. Therefore, predict() returns only a dummy * prediction. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0, + bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on branches in @@ -76,7 +76,7 @@ class PerceptronPredictor : public BranchPredictor { /** Keep the last ftq entry as a separate variable to be reused for loops * in the event that the ftq_ is empty by the time the next predict() is * called */ - std::pair lastFtqEntry_; + std::pair lastFtqEntry_; /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. Each bit represents a branch taken (1) or not diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index d09408d136..16ddfafe5e 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -40,9 +40,8 @@ GenericPredictor::~GenericPredictor() { ftq_.clear(); } -BranchPrediction GenericPredictor::predict( - uint64_t address, BranchType type, int64_t knownOffset, - bool isLoop) { +BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, + int64_t knownOffset, bool isLoop) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -56,8 +55,8 @@ BranchPrediction GenericPredictor::predict( // Add branch to the back of the ftq ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); // Speculatively update the global history - globalHistory_ = ((globalHistory_ << 1) | lastFtqEntry_.first) & - globalHistoryMask_; + globalHistory_ = + ((globalHistory_ << 1) | lastFtqEntry_.first) & globalHistoryMask_; // prediction not required so return dummy prediction return {false, 0}; } diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 1f5a62d229..3ed2f2844e 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -46,9 +46,8 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // that the past dot product is the one most recently added to the ftq_ ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); // Update global history - globalHistory_ = - ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & - globalHistoryMask_; + globalHistory_ = ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & + globalHistoryMask_; // Return dummy prediction return {false, 0}; } @@ -127,7 +126,6 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t hashedIndex = ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); - std::vector perceptron = btb_[hashedIndex].first; // Work out the most recent prediction From 75f41703da1ad560870101911b22f6d83765badd Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 16:12:21 +0100 Subject: [PATCH 133/191] clang format --- test/unit/pipeline/FetchUnitTest.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 79092d2e5e..f15b0ecedc 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -279,8 +279,8 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff, false)).WillOnce - (Return(pred)); + EXPECT_CALL(predictor, predict(20, bType, knownOff, false)) + .WillOnce(Return(pred)); fetchUnit.tick(); // Ensure on next tick, predecode is not called From c1ba45d41d4876e41a65a8f053be4513b07fe39d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 7 May 2024 16:35:11 +0100 Subject: [PATCH 134/191] adding flush asserts --- .../simeng/branchpredictors/GenericPredictor.hh | 1 + .../simeng/branchpredictors/PerceptronPredictor.hh | 1 + src/lib/branchpredictors/GenericPredictor.cc | 4 +++- src/lib/branchpredictors/PerceptronPredictor.cc | 11 +++++++++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index db46df59b7..d831b1c0a1 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index b9b147e579..9a00fcfb39 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 16ddfafe5e..ef42abd3f0 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -151,7 +151,9 @@ void GenericPredictor::flush(uint64_t address) { rasHistory_.erase(it); } - // If possible, pop instruction from FTQ + assert((ftq_.size() > 0) && + "Cannot flush instruction from Branch Predictor " + "when the ftq is empty"); ftq_.pop_back(); // Roll back global history diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 3ed2f2844e..1f39a35719 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -10,6 +10,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Build BTB based on config options uint32_t btbSize = (1 << btbBits_); btb_.resize(btbSize); + // Initialise perceptron values with 0 for the global history weights, and 1 // for the bias weight; and initialise the target with 0 (i.e., unknown) for (uint32_t i = 0; i < btbSize; i++) { @@ -37,17 +38,19 @@ PerceptronPredictor::~PerceptronPredictor() { BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop) { - // If branch is in a loop then a new prediction is not required. Just need + // If branch is in a loop then a new prediction is not required. Just need // to update ftq and global history if (isLoop) { // Add branch to the ftq using the past dot product in lieu of a new - // prediction. Because the loop buffer supplies only if there have been + // prediction. Because the loop buffer supplies only if there have been // no branch instructions since the branch defining the loop, we know // that the past dot product is the one most recently added to the ftq_ ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); + // Update global history globalHistory_ = ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & globalHistoryMask_; + // Return dummy prediction return {false, 0}; } @@ -65,6 +68,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // Get dot product of perceptron and history int64_t Pout = getDotProduct(perceptron, globalHistory_); + // Determine direction prediction based on its sign bool direction = (Pout >= 0); @@ -186,6 +190,9 @@ void PerceptronPredictor::flush(uint64_t address) { rasHistory_.erase(it); } + assert((ftq_.size() > 0) && + "Cannot flush instruction from Branch Predictor " + "when the ftq is empty"); ftq_.pop_back(); // Roll back global history From 36a7f1a28455c16ec4701a87a84ee5df83e183a0 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 12:30:35 +0100 Subject: [PATCH 135/191] Responding to PR comments --- .../branchpredictors/PerceptronPredictor.hh | 5 ++- src/lib/models/outoforder/Core.cc | 41 ++++--------------- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 9a00fcfb39..7034fe9201 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -71,7 +71,10 @@ class PerceptronPredictor : public BranchPredictor { /** Fetch Target Queue containing the dot product of the perceptron and the * global history; and the global history, both at the time of prediction, - * for each of the branches that are currently unresolved. */ + * for each of the branch instructions that are currently unresolved. The dot + * product represents the confidence of the perceptrons direction + * prediction and is needed for a correct update when the branch + * instruction is resolved. */ std::deque> ftq_; /** Keep the last ftq entry as a separate variable to be reused for loops diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 2cb1b28be4..ff95e94275 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -259,8 +259,8 @@ void Core::raiseException(const std::shared_ptr& instruction) { } void Core::handleException() { - // Check the buffer entries to see if they are branch instructions. If so, - // flush them from the BP + // Check for branch instructions in buffer, and flush them from the BP. + // Then empty the buffers fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); @@ -343,31 +343,15 @@ void Core::flushIfNeeded() { targetAddress = reorderBuffer_.getFlushAddress(); } + // Check for branch instructions in buffer, and flush them from the BP. + // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { - auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - } + fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - for (size_t slot = 0; slot < decodeToRenameBuffer_.getWidth(); slot++) { - auto& uop = decodeToRenameBuffer_.getTailSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - uop = decodeToRenameBuffer_.getHeadSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - predictor_.flush(uop->getInstructionAddress()); - } - } + decodeToRenameBuffer_.flushBranchMicroOps(predictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -389,18 +373,11 @@ void Core::flushIfNeeded() { // Update PC and wipe Fetch/Decode buffer. targetAddress = decodeUnit_.getFlushAddress(); + // Check for branch instructions in buffer, and flush them from the BP. + // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - for (size_t slot = 0; slot < fetchToDecodeBuffer_.getWidth(); slot++) { - auto& macroOp = fetchToDecodeBuffer_.getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = fetchToDecodeBuffer_.getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - predictor_.flush(macroOp[0]->getInstructionAddress()); - } - } + fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); From 3298bea1f42dc182b11c6e3e6b0a9616709def1f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 13:00:58 +0100 Subject: [PATCH 136/191] Responding to PR comments --- src/include/simeng/pipeline/FetchUnit.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 7 ++++--- src/lib/models/outoforder/Core.cc | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/pipeline/FetchUnit.hh b/src/include/simeng/pipeline/FetchUnit.hh index 035942caac..0eebb3c6b9 100644 --- a/src/include/simeng/pipeline/FetchUnit.hh +++ b/src/include/simeng/pipeline/FetchUnit.hh @@ -121,7 +121,7 @@ class FetchUnit { /** The amount of data currently in the fetch buffer. */ uint16_t bufferedBytes_ = 0; - /** The number of branch instructions that were executed. */ + /** The number of branch instructions that were fetched. */ uint64_t branchesFetched_ = 0; /** Let the following PipelineFetchUnitTest derived classes be a friend of diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index ef42abd3f0..d6298c8cb6 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -22,9 +22,10 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // Create branch prediction structures btb_ = std::vector>(1 << btbBits_, {satCntVal, 0}); - // Alter globalHistoryLength_ value to better suit required format in update() - // Multiply original globalHistoryLength_ by two so that extra branch - // outcomes are stored to allow rolling back the speculatively updated + + // Generate a bitmask that is used to ensure only the relevant number of + // bits are stored in the global history. This is two times the + // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index ff95e94275..3c7acb3c42 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -269,6 +269,8 @@ void Core::handleException() { decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); + // instructions in this buffer are already accounted for in the ROB so no + // need to check for branch instructions in this buffer renameToDispatchBuffer_.fill(nullptr); renameToDispatchBuffer_.stall(false); From 305c90468dd65ad5fd01393813c1873b3d691cba Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 16:29:11 +0100 Subject: [PATCH 137/191] Moving words around --- docs/sphinx/developer/components/branchPred.rst | 4 ++-- src/lib/branchpredictors/PerceptronPredictor.cc | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 767fd1bead..359682b80f 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures and for retrieving a direction from the perceptrons, a global history can be utilised. The global history value uses n-bits to store the n most recent branch direction outcomes, with the most-significant bit being the oldest. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 1f39a35719..40a22dae7f 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -22,6 +22,10 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // Set up training threshold according to empirically determined formula trainingThreshold_ = (uint64_t)((1.93 * globalHistoryLength_) + 14); + // Generate a bitmask that is used to ensure only the relevant number of + // bits are stored in the global history. This is two times the + // globalHistoryLength_ to allow rolling back of the speculatively updated + // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() From 15b103726efc5d78026ad5cbc1e592c4617a3163 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 16:30:45 +0100 Subject: [PATCH 138/191] Moving words around --- src/lib/models/outoforder/Core.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 3c7acb3c42..4d58152b5b 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -269,7 +269,7 @@ void Core::handleException() { decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); - // instructions in this buffer are already accounted for in the ROB so no + // Instructions in this buffer are already accounted for in the ROB so no // need to check for branch instructions in this buffer renameToDispatchBuffer_.fill(nullptr); renameToDispatchBuffer_.stall(false); From b612c3de1d7cabe8b005488b79da51fa17e7938f Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 10 May 2024 16:31:24 +0100 Subject: [PATCH 139/191] Moving words around --- src/lib/models/outoforder/Core.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 4d58152b5b..5b90cf9994 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -357,6 +357,8 @@ void Core::flushIfNeeded() { decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); + // Instructions in this buffer are already accounted for in the ROB so no + // need to check for branch instructions in this buffer renameToDispatchBuffer_.fill(nullptr); renameToDispatchBuffer_.stall(false); From 9e701bc10b10ff222c24bc4c025a86a973598aca Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:40:37 +0100 Subject: [PATCH 140/191] Rebasing --- src/include/simeng/Instruction.hh | 2 +- test/unit/pipeline/ReorderBufferTest.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 6385995a7b..d202565ab9 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -156,7 +156,7 @@ class Instruction { "Branch misprediction check requires instruction to have executed"); // Flag as mispredicted if taken state was wrongly predicted, or taken // and predicted target is wrong - return (branchTaken_ != prediction_.isTaken || + return ((branchTaken_ != prediction_.isTaken) || (branchTaken_ && (prediction_.target != branchAddress_))); } diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index aa59fe0448..3514e583f3 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -438,7 +438,7 @@ TEST_F(ReorderBufferTest, branch) { EXPECT_EQ(loopBoundaryAddr, insnAddr); // Check that branch misprediction metrics have been correctly collected - EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); + EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 4); } // Tests that only those destination registers which have been renamed are From a402dcf58ba0aac2840e5af5373784a1946fba31 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 13 May 2024 13:15:45 +0100 Subject: [PATCH 141/191] undoing last push --- src/include/simeng/Instruction.hh | 2 +- test/unit/pipeline/ReorderBufferTest.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index d202565ab9..d2b85068e0 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -157,7 +157,7 @@ class Instruction { // Flag as mispredicted if taken state was wrongly predicted, or taken // and predicted target is wrong return ((branchTaken_ != prediction_.isTaken) || - (branchTaken_ && (prediction_.target != branchAddress_))); + (prediction_.target != branchAddress_)); } /** Check whether an exception has been encountered while processing this diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 3514e583f3..aa59fe0448 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -438,7 +438,7 @@ TEST_F(ReorderBufferTest, branch) { EXPECT_EQ(loopBoundaryAddr, insnAddr); // Check that branch misprediction metrics have been correctly collected - EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 4); + EXPECT_EQ(reorderBuffer.getBranchMispredictedCount(), 8); } // Tests that only those destination registers which have been renamed are From 7b336ace99a821353b84184ffe56538a5e2f4eae Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 14 May 2024 10:52:16 +0100 Subject: [PATCH 142/191] Finessing update logic re target adresses --- src/include/simeng/Instruction.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 5 ++++- src/lib/branchpredictors/PerceptronPredictor.cc | 4 +++- src/lib/pipeline/FetchUnit.cc | 8 ++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index d2b85068e0..6bdeb1e401 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -178,7 +178,7 @@ class Instruction { * executing it. */ uint16_t getStallCycles() const { return stallCycles_; } - /** Retrieve the number of cycles this instruction will take to be prcoessed + /** Retrieve the number of cycles this instruction will take to be processed * by the LSQ. */ uint16_t getLSQLatency() const { return lsqExecutionLatency_; } diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index d6298c8cb6..b8dae30339 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -120,7 +120,10 @@ void GenericPredictor::update(uint64_t address, bool isTaken, } // Update BTB entry - btb_[hashedIndex] = {satCntVal, targetAddress}; + btb_[hashedIndex].first = satCntVal; + if (isTaken) { + btb_[hashedIndex].second = targetAddress; + } // Update global history if prediction was incorrect if (prevPrediction != isTaken) { diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 40a22dae7f..150947ce47 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -164,7 +164,9 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, } btb_[hashedIndex].first = perceptron; - btb_[hashedIndex].second = targetAddress; + if (isTaken) { + btb_[hashedIndex].second = targetAddress; + } // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index f52d6f1599..07c8c77708 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -203,12 +203,12 @@ void FetchUnit::tick() { bufferOffset += bytesRead; bufferedBytes_ -= bytesRead; - if (!prediction.isTaken) { - // Predicted as not taken; increment PC to next instruction - pc_ += bytesRead; - } else { + if (prediction.isTaken) { // Predicted as taken; set PC to predicted target address pc_ = prediction.target; + } else { + // Predicted as not taken; increment PC to next instruction + pc_ += bytesRead; } if (pc_ >= programByteLength_) { From 6148a4ad2082a57e5a398ba5fdda7c5585923f3a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:10:57 +0100 Subject: [PATCH 143/191] Updating predict() comment in BranchPredictor.hh --- .../simeng/branchpredictors/BranchPredictor.hh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index fe5aa077b9..85c2e9c7cc 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -46,11 +46,14 @@ class BranchPredictor { public: virtual ~BranchPredictor(){}; - /** Generate a branch prediction for the specified instruction address with a - * branch type and possible known branch offset. There is an optional - * boolean argument for if the branch is a part of a loop, in which case - * the fetch unit does not require a new prediction and so only a dummy - * prediction is returned. */ + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset; defaults to 0 meaning offset is not + * known. Returns a branch direction and branch target address. There is + * also an optional boolean argument for whether or not the branch has + * been identified as being a part of a loop. If the branch is a loop + * branch, then the fetch unit will reuse a previous prediction and so no + * new prediction is required. Therefore, predict() returns only a dummy + * prediction. */ virtual BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop = false) = 0; From cc19a8dc16bac606564a7afbb991aa70aa520029 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:13:30 +0100 Subject: [PATCH 144/191] Updating predict() comment in BranchPredictor.hh --- src/include/simeng/branchpredictors/BranchPredictor.hh | 6 +++--- src/include/simeng/branchpredictors/GenericPredictor.hh | 8 +++++--- .../simeng/branchpredictors/PerceptronPredictor.hh | 8 +++++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 85c2e9c7cc..ad8cf335fa 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -58,9 +58,9 @@ class BranchPredictor { int64_t knownOffset, bool isLoop = false) = 0; - /** Provide branch results to update the prediction model for the specified - * instruction address. Update must be called on instructions in program - * order. */ + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on branches in + * program order. */ virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) = 0; diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index d831b1c0a1..fdf617a59d 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -45,9 +45,11 @@ class GenericPredictor : public BranchPredictor { void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Flushes the most recently predicted branch from the BP. Address is - * required to ensure that only the correct branch is removed from the RAS. - * */ + /** Provides flushing behaviour for the implemented branch prediction schemes + * via the instruction address. Branches must be flushed in reverse + * program order (though, if a block of n instructions is being flushed at + * once, the exact order that the individual instructions within this block + * are flushed does not matter so long as they are all flushed). */ void flush(uint64_t address) override; private: diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 7034fe9201..6a7df13976 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -48,9 +48,11 @@ class PerceptronPredictor : public BranchPredictor { void update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type) override; - /** Flushes the most recently predicted branch from the BP. Address is - * required to ensure that only the correct branch is removed from the RAS. - * */ + /** Provides flushing behaviour for the implemented branch prediction schemes + * via the instruction address. Branches must be flushed in reverse + * program order (though, if a block of n instructions is being flushed at + * once, the exact order that the individual instructions within this block + * are flushed does not matter so long as they are all flushed). */ void flush(uint64_t address) override; private: From e6632231a04c51a79b152c46b82ff8ca622661b2 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:17:35 +0100 Subject: [PATCH 145/191] Updating haeders and comments --- src/include/simeng/pipeline/ExecuteUnit.hh | 1 - src/include/simeng/pipeline/PipelineBuffer.hh | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/include/simeng/pipeline/ExecuteUnit.hh b/src/include/simeng/pipeline/ExecuteUnit.hh index 450ad4b384..cd11eb23d6 100644 --- a/src/include/simeng/pipeline/ExecuteUnit.hh +++ b/src/include/simeng/pipeline/ExecuteUnit.hh @@ -4,7 +4,6 @@ #include #include "simeng/Instruction.hh" -#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/pipeline/PipelineBuffer.hh" namespace simeng { diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index 342355eaf2..bd7c565735 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -75,8 +75,8 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } - /** flush branches in the buffer from the branch predictor, where the - * buffer contains microops */ + /** Flush branches in the buffer from the branch predictor, where the + * buffer contains micro-ops */ void flushBranchMicroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& uop = getTailSlots()[slot]; @@ -90,8 +90,8 @@ class PipelineBuffer { } } - /** flush branches in the buffer from the branch predictor, where the - * buffer contains macroops */ + /** Flush branches in the buffer from the branch predictor, where the + * buffer contains macro-ops */ void flushBranchMacroOps(BranchPredictor& branchPredictor) { for (size_t slot = 0; slot < width; slot++) { auto& macroOp = getTailSlots()[slot]; From 7d6ac3a27014e2e3d534475a4605cd4a0206a170 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:18:34 +0100 Subject: [PATCH 146/191] Fixing indentation in CMakeLists.txt --- src/lib/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ac393b19c2..ae659e2338 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -14,9 +14,9 @@ set(SIMENG_SOURCES arch/riscv/Instruction_decode.cc arch/riscv/Instruction_execute.cc arch/riscv/InstructionMetadata.cc - branchpredictors/AlwaysNotTakenPredictor.cc - branchpredictors/GenericPredictor.cc - branchpredictors/PerceptronPredictor.cc + branchpredictors/AlwaysNotTakenPredictor.cc + branchpredictors/GenericPredictor.cc + branchpredictors/PerceptronPredictor.cc config/ModelConfig.cc kernel/Linux.cc kernel/LinuxProcess.cc From 0067388d77e45a1e084b42cec135a2198e4e4a74 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 24 May 2024 11:30:37 +0100 Subject: [PATCH 147/191] Updating metric language in Core.cc --- src/lib/models/outoforder/Core.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 5b90cf9994..1d80a99afc 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -224,11 +224,11 @@ std::map Core::getStats() const { auto backendStalls = dispatchIssueUnit_.getBackendStalls(); auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); - uint64_t totalBranchesExecuted = fetchUnit_.getBranchFetchedCount(); + uint64_t totalBranchesFetched = fetchUnit_.getBranchFetchedCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesExecuted); + static_cast(totalBranchesFetched); std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; @@ -246,7 +246,7 @@ std::map Core::getStats() const { {"issue.frontendStalls", std::to_string(frontendStalls)}, {"issue.backendStalls", std::to_string(backendStalls)}, {"issue.portBusyStalls", std::to_string(portBusyStalls)}, - {"branch.executed", std::to_string(totalBranchesExecuted)}, + {"branch.fetched", std::to_string(totalBranchesFetched)}, {"branch.mispredict", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}, {"lsq.loadViolations", From b4fab7e3383cf6496509652a60ebaffdcc8d30b6 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 28 May 2024 12:44:39 +0100 Subject: [PATCH 148/191] Updating variable name in Core class --- src/include/simeng/models/outoforder/Core.hh | 2 +- src/lib/models/outoforder/Core.cc | 12 ++++++------ test/unit/pipeline/FetchUnitTest.cc | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/include/simeng/models/outoforder/Core.hh b/src/include/simeng/models/outoforder/Core.hh index e7d2d5c40f..82c3de37cd 100644 --- a/src/include/simeng/models/outoforder/Core.hh +++ b/src/include/simeng/models/outoforder/Core.hh @@ -136,7 +136,7 @@ class Core : public simeng::Core { std::shared_ptr exceptionGeneratingInstruction_; /** Reference to the current branch predictor */ - BranchPredictor& predictor_; + BranchPredictor& branchPredictor_; }; } // namespace outoforder diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 1d80a99afc..459cb552e9 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -73,7 +73,7 @@ Core::Core(memory::MemoryInterface& instructionMemory, .as()), portAllocator_(portAllocator), commitWidth_(config["Pipeline-Widths"]["Commit"].as()), - predictor_(branchPredictor) { + branchPredictor_(branchPredictor) { for (size_t i = 0; i < config["Execution-Units"].num_children(); i++) { // Create vector of blocking groups std::vector blockingGroups = {}; @@ -261,11 +261,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check for branch instructions in buffer, and flush them from the BP. // Then empty the buffers - fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); + fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - decodeToRenameBuffer_.flushBranchMicroOps(predictor_); + decodeToRenameBuffer_.flushBranchMicroOps(branchPredictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -349,11 +349,11 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); + fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - decodeToRenameBuffer_.flushBranchMicroOps(predictor_); + decodeToRenameBuffer_.flushBranchMicroOps(branchPredictor_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -381,7 +381,7 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - fetchToDecodeBuffer_.flushBranchMacroOps(predictor_); + fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index f15b0ecedc..0822e63de9 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -418,7 +418,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set the first expectation from the predictor to be true so a loop body will // be detected - EXPECT_CALL(predictor, predict(_, _, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, false)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -430,7 +430,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _, _)) + EXPECT_CALL(predictor, predict(_, _, _, false)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the From f9b9f552c2d2d4cf7cb8a0f026167641b2553ef9 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 28 May 2024 14:39:38 +0100 Subject: [PATCH 149/191] Adding assert to branch predictors to confirm that they are being updated in program order --- .../AlwaysNotTakenPredictor.hh | 10 +- .../branchpredictors/BranchPredictor.hh | 7 +- .../branchpredictors/GenericPredictor.hh | 11 +- .../branchpredictors/PerceptronPredictor.hh | 11 +- .../AlwaysNotTakenPredictor.cc | 3 +- src/lib/branchpredictors/GenericPredictor.cc | 9 +- .../branchpredictors/PerceptronPredictor.cc | 9 +- src/lib/pipeline/DecodeUnit.cc | 2 +- src/lib/pipeline/ReorderBuffer.cc | 3 +- test/unit/GenericPredictorTest.cc | 126 +++++++++--------- test/unit/MockBranchPredictor.hh | 5 +- test/unit/PerceptronPredictorTest.cc | 126 +++++++++--------- test/unit/pipeline/DecodeUnitTest.cc | 3 +- test/unit/pipeline/ReorderBufferTest.cc | 24 ++-- 14 files changed, 194 insertions(+), 155 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index cbab63f0c3..6869f2e17e 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -13,10 +13,12 @@ class AlwaysNotTakenPredictor : public BranchPredictor { BranchPrediction predict(uint64_t address, BranchType type, int64_t knownOffset, bool isLoop = false) override; - /** Provide branch results to update the prediction model for the specified - * instruction address. As this model is static, this does nothing. */ - void update(uint64_t address, bool taken, uint64_t targetAddress, - BranchType type) override; + /** Updates appropriate predictor model objects based on the address, type and + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ + void update(uint64_t address, bool isTaken, uint64_t targetAddress, + BranchType type, uint64_t instructionId) override; /** Provide flush logic for branch prediction scheme. As there's no flush * logic for an always taken predictor, this does nothing. */ diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index ad8cf335fa..4aeeb2b97e 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -59,10 +59,11 @@ class BranchPredictor { bool isLoop = false) = 0; /** Updates appropriate predictor model objects based on the address, type and - * outcome of the branch instruction. Update must be called on branches in - * program order. */ + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ virtual void update(uint64_t address, bool isTaken, uint64_t targetAddress, - BranchType type) = 0; + BranchType type, uint64_t instructionId) = 0; /** Provides flushing behaviour for the implemented branch prediction schemes * via the instruction address. Branches must be flushed in reverse diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index fdf617a59d..1b1fb3151e 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -40,10 +40,11 @@ class GenericPredictor : public BranchPredictor { bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and - * outcome of the branch instruction. Update must be called on branches in - * program order. */ + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, - BranchType type) override; + BranchType type, uint64_t instructionId) override; /** Provides flushing behaviour for the implemented branch prediction schemes * via the instruction address. Branches must be flushed in reverse @@ -94,6 +95,10 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; + + /** The Id of the last instruction that update was called on -- used to + * ensure that update is called in program order. */ + uint64_t lastUpdatedInstructionId = 0; }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 6a7df13976..5cc90f033a 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -43,10 +43,11 @@ class PerceptronPredictor : public BranchPredictor { bool isLoop = false) override; /** Updates appropriate predictor model objects based on the address, type and - * outcome of the branch instruction. Update must be called on branches in - * program order. */ + * outcome of the branch instruction. Update must be called on + * branches in program order. To check this, instructionId is also passed + * to this function. */ void update(uint64_t address, bool isTaken, uint64_t targetAddress, - BranchType type) override; + BranchType type, uint64_t instructionId) override; /** Provides flushing behaviour for the implemented branch prediction schemes * via the instruction address. Branches must be flushed in reverse @@ -110,6 +111,10 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; + + /** The Id of the last instruction that update was called on -- used to + * ensure that update is called in program order. */ + uint64_t lastUpdatedInstructionId = 0; }; } // namespace simeng diff --git a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index 847e32740e..bfe342cce5 100644 --- a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -8,7 +8,8 @@ BranchPrediction AlwaysNotTakenPredictor::predict( } void AlwaysNotTakenPredictor::update(uint64_t address, bool taken, - uint64_t targetAddress, BranchType type) {} + uint64_t targetAddress, BranchType type, + uint64_t instructionId) {} void AlwaysNotTakenPredictor::flush(uint64_t address) {} diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index b8dae30339..cc6749f0e0 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -105,7 +105,14 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, } void GenericPredictor::update(uint64_t address, bool isTaken, - uint64_t targetAddress, BranchType type) { + uint64_t targetAddress, BranchType type, + uint64_t instructionId) { + // Make sure that this function is called in program order; and then update + // the lastUpdatedInstructionId variable + assert(instructionId >= lastUpdatedInstructionId && + (lastUpdatedInstructionId = instructionId) >= 0 && + "Update not called on branch instructions in program order"); + // Get previous prediction and index calculated from the FTQ bool prevPrediction = ftq_.front().first; uint64_t hashedIndex = ftq_.front().second; diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 150947ce47..4a28894945 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -123,7 +123,14 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, } void PerceptronPredictor::update(uint64_t address, bool isTaken, - uint64_t targetAddress, BranchType type) { + uint64_t targetAddress, BranchType type, + uint64_t instructionId) { + // Make sure that this function is called in program order; and then update + // the lastUpdatedInstructionId variable + assert(instructionId >= lastUpdatedInstructionId && + (lastUpdatedInstructionId = instructionId) >= 0 && + "Update not called on branch instructions in program order"); + // Retrieve the previous global history and branch direction prediction from // the front of the ftq (assumes branches are updated in program order). int64_t prevPout = ftq_.front().first; diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 8748690488..31df59fa66 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -64,7 +64,7 @@ void DecodeUnit::tick() { if (!uop->isBranch()) { // Non-branch incorrectly predicted as a branch; let the predictor know predictor_.update(uop->getInstructionAddress(), false, pc_, - uop->getBranchType()); + uop->getBranchType(), uop->getInstructionId()); } // Remove macro-operations in microOps_ buffer after macro-operation // decoded in this cycle diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 47b231e866..cf5c2c52bb 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -157,7 +157,8 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { // updates is correct) if (uop->isBranch()) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType()); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId()); // Update the branch misprediction counter if (uop->wasBranchMispredicted()) branchMispredicts_++; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 0c698cd276..bca76c1ca9 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -87,15 +87,15 @@ TEST_F(GenericPredictorTest, Hit) { "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 4); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); @@ -112,114 +112,114 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 6); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x7C, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 10); // Spool up second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 12); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 13); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 14); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 15); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 16); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 17); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 18); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 19); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 22); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 23); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 24); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 25); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 26); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 27); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 28); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 29); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 30); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0x7C, true, 0xAB, BranchType::Conditional); + predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 32); // Recreate second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 33); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 34); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 35); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 36); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 37); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 38); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 39); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 40); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 41); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 16, BranchType::Conditional); + predictor.update(0, false, 16, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 43); } // Test Flush of RAS functionality @@ -269,43 +269,43 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x4); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 10); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); } } // namespace simeng diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 56777c0846..2ca46d4133 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -11,8 +11,9 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(predict, BranchPrediction(uint64_t address, BranchType type, int64_t knownTarget, bool getPrediction)); - MOCK_METHOD4(update, void(uint64_t address, bool taken, - uint64_t targetAddress, BranchType type)); + MOCK_METHOD5(update, void(uint64_t address, bool taken, + uint64_t targetAddress, BranchType type, + uint64_t instructionId)); MOCK_METHOD1(flush, void(uint64_t address)); }; diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 15d6c88250..01daf80f2a 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -76,15 +76,15 @@ TEST_F(PerceptronPredictorTest, Hit) { "Global-History-Length: 1, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 16, BranchType::Conditional); + predictor.update(0, true, 16, BranchType::Conditional, 4); auto prediction = predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); @@ -100,114 +100,114 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 6); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x7C, false, 0x80, BranchType::Conditional); + predictor.update(0x7C, false, 0x80, BranchType::Conditional, 10); // Spool up second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 12); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 13); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 14); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 15); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 16); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 17); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 18); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 19); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0); // Set entry in BTB - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 22); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 23); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 24); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 25); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 26); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 27); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 28); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 29); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 30); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_FALSE(prediction.isTaken); EXPECT_EQ(prediction.target, 0x80); // Set entry in BTB - predictor.update(0x7C, true, 0x80, BranchType::Conditional); + predictor.update(0x7C, true, 0x80, BranchType::Conditional, 32); // Recreate second global history pattern predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 33); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 34); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 35); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 36); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 37); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 38); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 39); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 40); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 41); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, false, 4, BranchType::Conditional); + predictor.update(0, false, 4, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xBA); - predictor.update(0x7C, true, 0xBA, BranchType::Conditional); + predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 43); } // Test Flush of RAS functionality @@ -255,17 +255,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 0); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 1); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 2); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 3); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 4); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); // Defaults to not-taken @@ -273,27 +273,27 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // Should predict target of address + 4 EXPECT_EQ(prediction.target, 0x103); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 7); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 8); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 9); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 10); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 11); predictor.predict(0, BranchType::Conditional, 0, true); - predictor.update(0, true, 4, BranchType::Conditional); + predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); EXPECT_TRUE(prediction.isTaken); EXPECT_EQ(prediction.target, 0xAB); // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional); + predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); } } // namespace simeng diff --git a/test/unit/pipeline/DecodeUnitTest.cc b/test/unit/pipeline/DecodeUnitTest.cc index f86dbc0caf..eed1ab60ae 100644 --- a/test/unit/pipeline/DecodeUnitTest.cc +++ b/test/unit/pipeline/DecodeUnitTest.cc @@ -82,7 +82,8 @@ TEST_F(PipelineDecodeUnitTest, Flush) { EXPECT_CALL(*uop, isBranch()).WillOnce(Return(false)); // Check the predictor is updated with the correct instruction address and PC - EXPECT_CALL(predictor, update(2, false, 1, BranchType::Unconditional)); + EXPECT_CALL(predictor, update(2, false, 1, BranchType::Unconditional, + uop->getInstructionId())); decodeUnit.tick(); diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index aa59fe0448..0f3bfced52 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -368,7 +368,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -376,7 +377,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -384,7 +386,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -393,7 +396,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -408,7 +412,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -416,7 +421,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -424,7 +430,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -433,7 +440,8 @@ TEST_F(ReorderBufferTest, branch) { reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType())); + uop->getBranchAddress(), uop->getBranchType(), + uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); From 76d7f778ce384b9d72b347c295faf902b5d19821 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 30 May 2024 13:54:03 +0100 Subject: [PATCH 150/191] Adding test and clang formatting --- test/unit/MockBranchPredictor.hh | 6 +-- test/unit/pipeline/FetchUnitTest.cc | 68 ++++++++++++++++++++++++- test/unit/pipeline/ReorderBufferTest.cc | 48 ++++++++--------- 3 files changed, 94 insertions(+), 28 deletions(-) diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 2ca46d4133..ad728db849 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -11,9 +11,9 @@ class MockBranchPredictor : public BranchPredictor { MOCK_METHOD4(predict, BranchPrediction(uint64_t address, BranchType type, int64_t knownTarget, bool getPrediction)); - MOCK_METHOD5(update, void(uint64_t address, bool taken, - uint64_t targetAddress, BranchType type, - uint64_t instructionId)); + MOCK_METHOD5(update, + void(uint64_t address, bool taken, uint64_t targetAddress, + BranchType type, uint64_t instructionId)); MOCK_METHOD1(flush, void(uint64_t address)); }; diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 0822e63de9..2a898cd666 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -94,7 +94,7 @@ TEST_P(PipelineFetchUnitTest, TickStalled) { EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_, _, _, _)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _, false)).Times(0); fetchUnit.tick(); @@ -745,6 +745,72 @@ TEST_P(PipelineFetchUnitTest, invalidMinBytesreadsDontComplete) { } } +// Test that the Fetch unit is correctly tallying the number of branch +// instructions fetched, and that the getBranchFetchedCount getter function +// returns the correct value +TEST_P(PipelineFetchUnitTest, branchesFetchedCountedIncorrectly) { + // Set instructions to be fetched from memory + memory::MemoryReadResult memReadResultA = { + {0x0, blockSize}, RegisterValue(0xFFFF, blockSize), 1}; + span nextBlockA = {&memReadResultA, 1}; + memory::MemoryReadResult memReadResultB = { + {0x10, blockSize}, RegisterValue(0xFFFF, blockSize), 1}; + span nextBlockB = {&memReadResultB, 1}; + EXPECT_CALL(memory, getCompletedReads()).WillRepeatedly(Return(nextBlockA)); + + ON_CALL(isa, getMaxInstructionSize()).WillByDefault(Return(insnMaxSizeBytes)); + + // Set the instructions to be returned from predecode + MacroOp mOp2 = {uopPtr2}; + ON_CALL(isa, predecode(_, _, Gt(0x8), _)) + .WillByDefault(DoAll(SetArgReferee<3>(mOp2), Return(4))); + ON_CALL(*uop2, isBranch()).WillByDefault(Return(true)); + MacroOp mOp = {uopPtr}; + ON_CALL(isa, predecode(_, _, Lt(0xC), _)) + .WillByDefault(DoAll(SetArgReferee<3>(mOp), Return(4))); + ON_CALL(*uop, isBranch()).WillByDefault(Return(false)); + EXPECT_CALL(predictor, predict(_, _, _, false)) + .WillOnce(Return(BranchPrediction({true, 0x0}))); + + // Fetch instructions from data block -- one branch instruction + for (int i = 0; i < 4; i++) { + fetchUnit.tick(); + } + + // Confirm that the correct number of fetched branches has been recorded by + // the Fetch Unit + EXPECT_EQ(fetchUnit.getBranchFetchedCount(), 1); + + // Fetch the next block of instructions from memory and change the expected + // outcome of the branch predictor + fetchUnit.requestFromPC(); + EXPECT_CALL(predictor, predict(_, _, _, false)) + .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); + + // Fetch instructions from data block -- one branch instruction + for (int i = 0; i < 4; i++) { + fetchUnit.tick(); + } + + // Confirm that the correct number of fetched branches has been recorded by + // the Fetch Unit + EXPECT_EQ(fetchUnit.getBranchFetchedCount(), 2); + + const memory::MemoryAccessTarget target = {0x10, blockSize}; + EXPECT_CALL(memory, getCompletedReads()).WillRepeatedly(Return(nextBlockB)); + EXPECT_CALL(memory, requestRead(target, _)).Times(1); + + // Fetch instructions from data block -- four branch instructions + fetchUnit.requestFromPC(); + for (int i = 0; i < 4; i++) { + fetchUnit.tick(); + } + + // Confirm that the correct number of fetched branches has been recorded by + // the Fetch Unit + EXPECT_EQ(fetchUnit.getBranchFetchedCount(), 6); +} + INSTANTIATE_TEST_SUITE_P(PipelineFetchUnitTests, PipelineFetchUnitTest, ::testing::Values(std::pair(2, 4), std::pair(4, 4))); diff --git a/test/unit/pipeline/ReorderBufferTest.cc b/test/unit/pipeline/ReorderBufferTest.cc index 0f3bfced52..ff3b63756d 100644 --- a/test/unit/pipeline/ReorderBufferTest.cc +++ b/test/unit/pipeline/ReorderBufferTest.cc @@ -367,27 +367,27 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -395,9 +395,9 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); @@ -411,27 +411,27 @@ TEST_F(ReorderBufferTest, branch) { // First pass through ROB -- seen count reset to 0 as new branch reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Second pass through ROB -- seen count = 1 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); // Third pass through ROB -- seen count = 2 reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_NE(loopBoundaryAddr, insnAddr); @@ -439,9 +439,9 @@ TEST_F(ReorderBufferTest, branch) { // loopBoundaryAddr updated reorderBuffer.reserve(uopPtr); EXPECT_CALL(*uop, isBranch()).Times(2); - EXPECT_CALL(predictor, update(4096, uop->wasBranchTaken(), - uop->getBranchAddress(), uop->getBranchType(), - uop->getInstructionId())); + EXPECT_CALL(predictor, + update(4096, uop->wasBranchTaken(), uop->getBranchAddress(), + uop->getBranchType(), uop->getInstructionId())); reorderBuffer.commit(1); EXPECT_EQ(loopBoundaryAddr, insnAddr); From f6a5b53e074cbe7787b19733fc9a5c32383ac6f1 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:09:20 +0100 Subject: [PATCH 151/191] rebase --- .../developer/components/branchPred.rst | 4 +- .../AlwaysNotTakenPredictor.hh | 2 +- .../branchpredictors/BranchPredictor.hh | 10 +- .../branchpredictors/GenericPredictor.hh | 15 +-- .../branchpredictors/PerceptronPredictor.hh | 15 +-- src/lib/branchpredictors/GenericPredictor.cc | 19 +--- .../branchpredictors/PerceptronPredictor.cc | 25 +---- src/lib/pipeline/FetchUnit.cc | 9 +- test/unit/GenericPredictorTest.cc | 104 +++++++++--------- test/unit/MockBranchPredictor.hh | 5 +- test/unit/PerceptronPredictorTest.cc | 104 +++++++++--------- test/unit/pipeline/FetchUnitTest.cc | 14 +-- 12 files changed, 127 insertions(+), 199 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 359682b80f..28ce96ddc8 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -5,7 +5,7 @@ SimEng's fetch unit is supplied with an instance of the abstract ``BranchPredict Access to the ``BranchPredictor`` is supported through the ``predict``, ``update``, and ``flush`` functions. ``predict`` provides a branch prediction, both target and direction, for a branch instruction. ``update`` updates the branch predictor's prediction mechanism on the actual outcome of a branch. ``flush`` provides algorithm specific flushing functionality. -The ``predict`` function is passed an instruction address, branch type, a possible known target, and optionally whether the branch is in a loop. The branch type argument currently supports the following types: +The ``predict`` function is passed an instruction address, branch type, and a possible known target. The branch type argument currently supports the following types: - ``Conditional`` - ``LoopClosing`` @@ -13,7 +13,7 @@ The ``predict`` function is passed an instruction address, branch type, a possib - ``SubroutineCall`` - ``Unconditional`` -The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. If the branch is a part of a loop, then only a dummy branch prediction is returned by ``predict``, as the fetch unit will reuse a previous branch prediction and so no new branch prediction is needed. +The usage of these parameters within a branch predictor's ``predict`` function is algorithm specific. The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index 6869f2e17e..ab186223b1 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -11,7 +11,7 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Generate a branch prediction for the specified instruction address; will * always predict not taken. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset, bool isLoop = false) override; + int64_t knownOffset) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 4aeeb2b97e..dbfc3e96fa 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -48,15 +48,9 @@ class BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. There is - * also an optional boolean argument for whether or not the branch has - * been identified as being a part of a loop. If the branch is a loop - * branch, then the fetch unit will reuse a previous prediction and so no - * new prediction is required. Therefore, predict() returns only a dummy - * prediction. */ + * known. Returns a branch direction and branch target address. */ virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset, - bool isLoop = false) = 0; + int64_t knownOffset) = 0; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 1b1fb3151e..cb5baa0169 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -29,15 +29,9 @@ class GenericPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. There is - * also an optional boolean argument for whether or not the branch has - * been identified as being a part of a loop. If the branch is a loop - * branch, then the fetch unit will reuse a previous prediction and so no - * new prediction is required. Therefore, predict() returns only a dummy - * prediction. */ + * known. Returns a branch direction and branch target address. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -65,11 +59,6 @@ class GenericPredictor : public BranchPredictor { * history state of branches that are currently unresolved */ std::deque> ftq_; - /** Keep the last ftq entry as a separate variable to be reused for loops - * in the event that the ftq_ is empty by the time the next predict() is - * called */ - std::pair lastFtqEntry_; - /** The number of bits used to form the saturating counter in a BTB entry. */ uint8_t satCntBits_; diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 5cc90f033a..eea6746b8b 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -32,15 +32,9 @@ class PerceptronPredictor : public BranchPredictor { /** Generate a branch prediction for the supplied instruction address, a * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. There is - * also an optional boolean argument for whether or not the branch has - * been identified as being a part of a loop. If the branch is a loop - * branch, then the fetch unit will reuse a previous prediction and so no - * new prediction is required. Therefore, predict() returns only a dummy - * prediction. */ + * known. Returns a branch direction and branch target address. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0, - bool isLoop = false) override; + int64_t knownOffset = 0) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -80,11 +74,6 @@ class PerceptronPredictor : public BranchPredictor { * instruction is resolved. */ std::deque> ftq_; - /** Keep the last ftq entry as a separate variable to be reused for loops - * in the event that the ftq_ is empty by the time the next predict() is - * called */ - std::pair lastFtqEntry_; - /** An n-bit history of previous branch directions where n is equal to * globalHistoryLength_. Each bit represents a branch taken (1) or not * taken (0), with the most recent branch being the least-significant-bit */ diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index cc6749f0e0..331ea2d22f 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -28,10 +28,6 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - - // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() - // calls in tests work. - lastFtqEntry_ = {true, 0}; } GenericPredictor::~GenericPredictor() { @@ -42,7 +38,7 @@ GenericPredictor::~GenericPredictor() { } BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset, bool isLoop) { + int64_t knownOffset) { // Get index via an XOR hash between the global history and the instruction // address. This hash is then ANDed to keep it within bounds of the btb. // The address is shifted to remove the two least-significant bits as these @@ -50,18 +46,6 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, uint64_t hashedIndex = ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - // If branch is in a loop then a new prediction is not required. Just need - // to update ftq and global history - if (isLoop) { - // Add branch to the back of the ftq - ftq_.emplace_back(lastFtqEntry_.first, hashedIndex); - // Speculatively update the global history - globalHistory_ = - ((globalHistory_ << 1) | lastFtqEntry_.first) & globalHistoryMask_; - // prediction not required so return dummy prediction - return {false, 0}; - } - // Get prediction from BTB bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); uint64_t target = @@ -95,7 +79,6 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // Store the hashed index for correct hashing in update() ftq_.emplace_back(prediction.isTaken, hashedIndex); - lastFtqEntry_ = {prediction.isTaken, hashedIndex}; // Speculatively update the global history globalHistory_ = diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 4a28894945..da40cf1e00 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -27,10 +27,6 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; - - // Set dummy lastFtqEntry value, needed to ensure that in-loop predict() - // calls in tests work. - lastFtqEntry_ = {1, 0}; } PerceptronPredictor::~PerceptronPredictor() { @@ -40,25 +36,7 @@ PerceptronPredictor::~PerceptronPredictor() { } BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset, - bool isLoop) { - // If branch is in a loop then a new prediction is not required. Just need - // to update ftq and global history - if (isLoop) { - // Add branch to the ftq using the past dot product in lieu of a new - // prediction. Because the loop buffer supplies only if there have been - // no branch instructions since the branch defining the loop, we know - // that the past dot product is the one most recently added to the ftq_ - ftq_.emplace_back(lastFtqEntry_.first, globalHistory_); - - // Update global history - globalHistory_ = ((globalHistory_ << 1) | (lastFtqEntry_.first >= 0)) & - globalHistoryMask_; - - // Return dummy prediction - return {false, 0}; - } - + int64_t knownOffset) { // Get the hashed index for the prediction table. XOR the global history with // the non-zero bits of the address, and then keep only the btbBits_ bits of // the output to keep it in bounds of the prediction table. @@ -112,7 +90,6 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // needs to be global history and not the hashed index as hashing loses // information and the global history is required for updating perceptrons. ftq_.emplace_back(Pout, globalHistory_); - lastFtqEntry_ = {Pout, globalHistory_}; // Speculatively update the global history based on the direction // prediction being made diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 07c8c77708..840b4df3d0 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -52,12 +52,9 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { - macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); - // Let the branch predictor know the prediction is being reused so that - // the FTQ can be kept up to date - branchPredictor_.predict(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset(), true); + macroOp[0]->setBranchPrediction(branchPredictor_.predict( + macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset())); branchesFetched_++; } diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index bca76c1ca9..de4b284df5 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -111,25 +111,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { "Fallback-Static-Predictor: Always-Not-Taken}}"); auto predictor = simeng::GenericPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 6); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -139,25 +139,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 10); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 12); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 13); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 14); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 15); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 16); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 17); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 18); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 19); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -167,25 +167,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 22); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 23); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 24); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 25); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 26); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 27); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 28); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 29); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 30); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -195,25 +195,25 @@ TEST_F(GenericPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xAB, BranchType::Conditional, 32); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 33); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 34); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 35); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 36); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 37); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 38); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 39); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 40); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 16, BranchType::Conditional, 41); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 16, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -268,17 +268,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -288,17 +288,17 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure default behaviour for first encounter prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index ad728db849..2727e6db51 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -8,9 +8,8 @@ namespace simeng { /** Mock implementation of the `BranchPredictor` interface. */ class MockBranchPredictor : public BranchPredictor { public: - MOCK_METHOD4(predict, - BranchPrediction(uint64_t address, BranchType type, - int64_t knownTarget, bool getPrediction)); + MOCK_METHOD3(predict, BranchPrediction(uint64_t address, BranchType type, + int64_t knownTarget)); MOCK_METHOD5(update, void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type, uint64_t instructionId)); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 01daf80f2a..87c3220e58 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -99,25 +99,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { "Global-History-Length: 10, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // Spool up first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 6); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -127,25 +127,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, false, 0x80, BranchType::Conditional, 10); // Spool up second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 12); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 13); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 14); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 15); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 16); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 17); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 18); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 19); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 20); // Ensure default behaviour for re-encounter but with different global history prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -155,25 +155,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0xBA, BranchType::Conditional, 21); // Recreate first global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 22); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 23); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 24); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 25); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 26); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 27); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 28); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 29); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 30); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 31); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -183,25 +183,25 @@ TEST_F(PerceptronPredictorTest, GlobalIndexing) { predictor.update(0x7C, true, 0x80, BranchType::Conditional, 32); // Recreate second global history pattern - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 33); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 34); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 35); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 36); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 37); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 38); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 39); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 40); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 41); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, false, 4, BranchType::Conditional, 42); // Get prediction prediction = predictor.predict(0x7C, BranchType::Conditional, 0); @@ -254,17 +254,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 5); // Ensure default behaviour for first encounter auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); @@ -276,17 +276,17 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0, true); + predictor.predict(0, BranchType::Conditional, 0); predictor.update(0, true, 4, BranchType::Conditional, 12); // Ensure prediction is correct with new target address prediction = predictor.predict(0xFF, BranchType::Conditional, 0); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 2a898cd666..2c1c99b69b 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -94,7 +94,7 @@ TEST_P(PipelineFetchUnitTest, TickStalled) { EXPECT_CALL(isa, predecode(_, _, _, _)).Times(0); - EXPECT_CALL(predictor, predict(_, _, _, false)).Times(0); + EXPECT_CALL(predictor, predict(_, _, _)).Times(0); fetchUnit.tick(); @@ -279,7 +279,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff, false)) + EXPECT_CALL(predictor, predict(20, bType, knownOff)) .WillOnce(Return(pred)); fetchUnit.tick(); @@ -326,7 +326,7 @@ TEST_P(PipelineFetchUnitTest, supplyFromLoopBuffer) { // Set the expectation from the predictor to be true so a loop body will // be detected - ON_CALL(predictor, predict(_, _, _, _)) + ON_CALL(predictor, predict(_, _, _)) .WillByDefault(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -418,7 +418,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Set the first expectation from the predictor to be true so a loop body will // be detected - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Set Loop Buffer state to be LoopBufferState::FILLING @@ -430,7 +430,7 @@ TEST_P(PipelineFetchUnitTest, idleLoopBufferDueToNotTakenBoundary) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Attempt to fill Loop Buffer but prevent it on a not taken outcome at the @@ -769,7 +769,7 @@ TEST_P(PipelineFetchUnitTest, branchesFetchedCountedIncorrectly) { ON_CALL(isa, predecode(_, _, Lt(0xC), _)) .WillByDefault(DoAll(SetArgReferee<3>(mOp), Return(4))); ON_CALL(*uop, isBranch()).WillByDefault(Return(false)); - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillOnce(Return(BranchPrediction({true, 0x0}))); // Fetch instructions from data block -- one branch instruction @@ -784,7 +784,7 @@ TEST_P(PipelineFetchUnitTest, branchesFetchedCountedIncorrectly) { // Fetch the next block of instructions from memory and change the expected // outcome of the branch predictor fetchUnit.requestFromPC(); - EXPECT_CALL(predictor, predict(_, _, _, false)) + EXPECT_CALL(predictor, predict(_, _, _)) .WillRepeatedly(Return(BranchPrediction({false, 0x0}))); // Fetch instructions from data block -- one branch instruction From 6c64a488abdf1d8f5cdadc4295ca136d582b004a Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:49:01 +0100 Subject: [PATCH 152/191] Adding better comments to speculativeGlobalHistory tests in generic and perceptrons predictor tests --- test/unit/GenericPredictorTest.cc | 80 +++++++++++++------------- test/unit/PerceptronPredictorTest.cc | 84 ++++++++++++++-------------- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index de4b284df5..a47957bab1 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -263,49 +263,51 @@ TEST_F(GenericPredictorTest, flush) { // Test that update correctly corrects the speculatively updated global history TEST_F(GenericPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {BTB-Tag-Bits: 2, Saturating-Count-Bits: 6, " + "{Branch-Predictor: {BTB-Tag-Bits: 6, Saturating-Count-Bits: 2, " "Global-History-Length: 6, RAS-entries: 10, Fallback-Static-Predictor: " "Always-Taken}}"); auto predictor = simeng::GenericPredictor(); - // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 5); - // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.isTaken); - EXPECT_EQ(prediction.target, 0x4); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); + BranchPrediction pred; - // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 12); - // Ensure default behaviour for first encounter - prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.isTaken); - EXPECT_EQ(prediction.target, 0xAB); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); + // Set up the target prediction for btb entry 000111 to be 65536. No other + // target predictions will be set during this test, so we can confirm that + // we are accessing this btb entry by on the basis of this target prediction + pred = predictor.predict(28, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set + predictor.update(28, true, 65536, BranchType::Conditional, 0); + + // Set up a speculative global history of 111111 on the basis of predictions + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + + // Get prediction for address 224 to access btb entry 000111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + // Confirm prediction target is 65536 + EXPECT_EQ(pred.target, 65536); + EXPECT_TRUE(pred.isTaken); + + // Now correct the speculative global history using updates + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + + // Now a prediction for address 0 should access btb entry 000111 + pred = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_EQ(pred.target, 65536); } } // namespace simeng diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 87c3220e58..5978a02d42 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -247,53 +247,53 @@ TEST_F(PerceptronPredictorTest, flush) { EXPECT_EQ(prediction.target, 12); } -// Test that update correctly corrects the speculatively updated gloabl history +// Test that update corrects the speculatively updated global history TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 2, " + "{Branch-Predictor: {Type: Perceptron, BTB-Tag-Bits: 6, " "Global-History-Length: 6, RAS-entries: 5}}"); auto predictor = simeng::PerceptronPredictor(); - // spool up a global history to set the target address - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 0); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 1); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 2); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 3); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 4); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 5); - // Ensure default behaviour for first encounter - auto prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - // Defaults to not-taken - EXPECT_FALSE(prediction.isTaken); - // Should predict target of address + 4 - EXPECT_EQ(prediction.target, 0x103); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 6); + BranchPrediction pred; - // recreate this global history but with incorrect predictions - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 7); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 8); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 9); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 10); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 11); - predictor.predict(0, BranchType::Conditional, 0); - predictor.update(0, true, 4, BranchType::Conditional, 12); - // Ensure prediction is correct with new target address - prediction = predictor.predict(0xFF, BranchType::Conditional, 0); - EXPECT_TRUE(prediction.isTaken); - EXPECT_EQ(prediction.target, 0xAB); - // Set entry in BTB - predictor.update(0xFF, true, 0xAB, BranchType::Conditional, 13); + // Set up the target prediction for btb entry 000111 to be 65536. No other + // target predictions will be set during this test, so we can confirm that + // we are accessing this btb entry by on the basis of this target prediction + pred = predictor.predict(28, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set + predictor.update(28, true, 65536, BranchType::Conditional, 0); + + // Set up a speculative global history of 111111 on the basis of predictions + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + EXPECT_TRUE(pred.isTaken); + EXPECT_EQ(pred.target, 0); + + // Get prediction for address 224 to access btb entry 000111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + // Confirm prediction target is 65536 + EXPECT_EQ(pred.target, 65536); + EXPECT_TRUE(pred.isTaken); + + // Now correct the speculative global history using updates + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + + // Now a prediction for address 0 should access btb entry 000111 + pred = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_EQ(pred.target, 65536); } } // namespace simeng From babb31415ac33e128bf3c4f81016e2e212e04ac5 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:54:09 +0100 Subject: [PATCH 153/191] Clang format --- test/unit/GenericPredictorTest.cc | 22 +++++++++++----------- test/unit/PerceptronPredictorTest.cc | 22 +++++++++++----------- test/unit/pipeline/FetchUnitTest.cc | 3 +-- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index a47957bab1..0c627f98f7 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -273,37 +273,37 @@ TEST_F(GenericPredictorTest, speculativeGlobalHistory) { // target predictions will be set during this test, so we can confirm that // we are accessing this btb entry by on the basis of this target prediction pred = predictor.predict(28, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken - EXPECT_EQ(pred.target, 0); // Target prediction not yet set + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set predictor.update(28, true, 65536, BranchType::Conditional, 0); // Set up a speculative global history of 111111 on the basis of predictions - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); // Get prediction for address 224 to access btb entry 000111 - pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 // Confirm prediction target is 65536 EXPECT_EQ(pred.target, 65536); EXPECT_TRUE(pred.isTaken); // Now correct the speculative global history using updates - predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 - predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 - predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 // Now a prediction for address 0 should access btb entry 000111 pred = predictor.predict(0, BranchType::Conditional, 0); diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 5978a02d42..db8c439032 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -259,37 +259,37 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // target predictions will be set during this test, so we can confirm that // we are accessing this btb entry by on the basis of this target prediction pred = predictor.predict(28, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken - EXPECT_EQ(pred.target, 0); // Target prediction not yet set + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + EXPECT_EQ(pred.target, 0); // Target prediction not yet set predictor.update(28, true, 65536, BranchType::Conditional, 0); // Set up a speculative global history of 111111 on the basis of predictions - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); // Get prediction for address 224 to access btb entry 000111 - pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); // GH = 111111 // Confirm prediction target is 65536 EXPECT_EQ(pred.target, 65536); EXPECT_TRUE(pred.isTaken); // Now correct the speculative global history using updates - predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 - predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 - predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 // Now a prediction for address 0 should access btb entry 000111 pred = predictor.predict(0, BranchType::Conditional, 0); diff --git a/test/unit/pipeline/FetchUnitTest.cc b/test/unit/pipeline/FetchUnitTest.cc index 2c1c99b69b..90870fb5e2 100644 --- a/test/unit/pipeline/FetchUnitTest.cc +++ b/test/unit/pipeline/FetchUnitTest.cc @@ -279,8 +279,7 @@ TEST_P(PipelineFetchUnitTest, fetchTakenBranchMidBlock) { EXPECT_CALL(*uop, getBranchType()).WillOnce(Return(bType)); EXPECT_CALL(*uop, getKnownOffset()).WillOnce(Return(knownOff)); BranchPrediction pred = {true, pc + knownOff}; - EXPECT_CALL(predictor, predict(20, bType, knownOff)) - .WillOnce(Return(pred)); + EXPECT_CALL(predictor, predict(20, bType, knownOff)).WillOnce(Return(pred)); fetchUnit.tick(); // Ensure on next tick, predecode is not called From 7d4f5d73a82139621620450a595485ae0705b710 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:33:00 +0100 Subject: [PATCH 154/191] Changing use of prediction in loopbuffer --- src/lib/pipeline/FetchUnit.cc | 7 ++-- test/unit/PerceptronPredictorTest.cc | 53 ++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 840b4df3d0..c0f6a5837a 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -52,9 +52,12 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { - macroOp[0]->setBranchPrediction(branchPredictor_.predict( + macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); + BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset())); + macroOp[0]->getKnownOffset()); + assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && + "New prediction differts from loop buffer prediction"); branchesFetched_++; } diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index db8c439032..5b348c620e 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -257,23 +257,53 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // Set up the target prediction for btb entry 000111 to be 65536. No other // target predictions will be set during this test, so we can confirm that - // we are accessing this btb entry by on the basis of this target prediction - pred = predictor.predict(28, BranchType::Conditional, 0); + // we are accessing this btb entry by on the basis of this target + // prediction. This takes a bit more setting up than the Generic predictor + // as perceptrons are more complicated than saturating counters. + predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(0, false, 4, BranchType::Conditional, 0); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(0, false, 4, BranchType::Conditional, 1); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken - EXPECT_EQ(pred.target, 0); // Target prediction not yet set - predictor.update(28, true, 65536, BranchType::Conditional, 0); + predictor.update(0, false, 4, BranchType::Conditional, 2); // GH = 000000 + predictor.predict(28, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(28, true, 65536, BranchType::Conditional, 3); // GH = 000001 + predictor.predict(24, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(24, true, 65536, BranchType::Conditional, 4); // GH = 000011 + predictor.predict(16, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(16, true, 65536, BranchType::Conditional, 5); // GH = 000111 + predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(0, true, 65536, BranchType::Conditional, 6); // GH = 001111 + predictor.predict(32, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(32, true, 65536, BranchType::Conditional, 7); // GH = 011111 + predictor.predict(96, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken + predictor.update(96, true, 65536, BranchType::Conditional, 8); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); // Should be set to taken + EXPECT_EQ(pred.target, 65536); // Should be set to 65536 + predictor.update(224, true, 65536, BranchType::Conditional, + 9); // GH = 111111 // Set up a speculative global history of 111111 on the basis of predictions - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000011 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 000111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 001111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); - pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 011111 + pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 0); pred = predictor.predict(4, BranchType::Conditional, 0); // GH = 111111 @@ -287,12 +317,13 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { EXPECT_TRUE(pred.isTaken); // Now correct the speculative global history using updates - predictor.update(4, false, 8, BranchType::Conditional, 1); // GH = 011111 - predictor.update(4, false, 8, BranchType::Conditional, 2); // GH = 001111 - predictor.update(4, false, 8, BranchType::Conditional, 3); // GH = 000111 + predictor.update(4, false, 8, BranchType::Conditional, 10); // GH = 011111 + predictor.update(4, false, 8, BranchType::Conditional, 11); // GH = 001111 + predictor.update(4, false, 8, BranchType::Conditional, 12); // GH = 000111 // Now a prediction for address 0 should access btb entry 000111 pred = predictor.predict(0, BranchType::Conditional, 0); + EXPECT_TRUE(pred.isTaken); EXPECT_EQ(pred.target, 65536); } From 7365e535e1e8e6d9c2c9ad41655a4092ed3afbbb Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:18:30 +0100 Subject: [PATCH 155/191] replacing = with == --- .../simeng/branchpredictors/BranchPredictor.hh | 2 +- test/unit/PerceptronPredictorTest.cc | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index dbfc3e96fa..3c0b66597a 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -20,7 +20,7 @@ struct BranchPrediction { /** Whether the branch will be taken. */ bool isTaken; - /** The branch instruction's target address. If `isTaken = false`, the value + /** The branch instruction's target address. If `isTaken == false`, the value * will be ignored. */ uint64_t target; diff --git a/test/unit/PerceptronPredictorTest.cc b/test/unit/PerceptronPredictorTest.cc index 5b348c620e..7768ab0ba0 100644 --- a/test/unit/PerceptronPredictorTest.cc +++ b/test/unit/PerceptronPredictorTest.cc @@ -261,32 +261,32 @@ TEST_F(PerceptronPredictorTest, speculativeGlobalHistory) { // prediction. This takes a bit more setting up than the Generic predictor // as perceptrons are more complicated than saturating counters. predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, false, 4, BranchType::Conditional, 0); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, false, 4, BranchType::Conditional, 1); // GH = 000000 + predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, false, 4, BranchType::Conditional, 2); // GH = 000000 + predictor.predict(28, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(28, true, 65536, BranchType::Conditional, 3); // GH = 000001 + predictor.predict(24, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(24, true, 65536, BranchType::Conditional, 4); // GH = 000011 + predictor.predict(16, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(16, true, 65536, BranchType::Conditional, 5); // GH = 000111 + predictor.predict(0, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(0, true, 65536, BranchType::Conditional, 6); // GH = 001111 + predictor.predict(32, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(32, true, 65536, BranchType::Conditional, 7); // GH = 011111 + predictor.predict(96, BranchType::Conditional, 0); - EXPECT_TRUE(pred.isTaken); // Default behaviour is to predict taken predictor.update(96, true, 65536, BranchType::Conditional, 8); // GH = 111111 + pred = predictor.predict(224, BranchType::Conditional, 0); EXPECT_TRUE(pred.isTaken); // Should be set to taken EXPECT_EQ(pred.target, 65536); // Should be set to 65536 From 1a7ed6326b55c4a759603b75bae6ecf1e3ba4918 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:57:00 +0100 Subject: [PATCH 156/191] Typo fix --- src/lib/pipeline/FetchUnit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index c0f6a5837a..c3f5d61c06 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -57,7 +57,7 @@ void FetchUnit::tick() { macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && - "New prediction differts from loop buffer prediction"); + "New prediction differs from loop buffer prediction"); branchesFetched_++; } From ada85e4721b8e93efd303b75afaa260bdd25885c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:17:16 +0100 Subject: [PATCH 157/191] rebase --- src/include/simeng/branchpredictors/GenericPredictor.hh | 2 +- .../simeng/branchpredictors/PerceptronPredictor.hh | 2 +- src/lib/branchpredictors/GenericPredictor.cc | 4 ++-- src/lib/branchpredictors/PerceptronPredictor.cc | 9 +++------ src/lib/pipeline/FetchUnit.cc | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index cb5baa0169..28f2ee5a81 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -87,7 +87,7 @@ class GenericPredictor : public BranchPredictor { /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId = 0; + [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index eea6746b8b..d3392b4c90 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -103,7 +103,7 @@ class PerceptronPredictor : public BranchPredictor { /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId = 0; + [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; }; } // namespace simeng diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 331ea2d22f..a79289a62c 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -92,8 +92,8 @@ void GenericPredictor::update(uint64_t address, bool isTaken, uint64_t instructionId) { // Make sure that this function is called in program order; and then update // the lastUpdatedInstructionId variable - assert(instructionId >= lastUpdatedInstructionId && - (lastUpdatedInstructionId = instructionId) >= 0 && + assert(instructionId >= lastUpdatedInstructionId_ && + (lastUpdatedInstructionId_ = instructionId) >= 0 && "Update not called on branch instructions in program order"); // Get previous prediction and index calculated from the FTQ diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index da40cf1e00..3c5337875a 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -104,8 +104,8 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t instructionId) { // Make sure that this function is called in program order; and then update // the lastUpdatedInstructionId variable - assert(instructionId >= lastUpdatedInstructionId && - (lastUpdatedInstructionId = instructionId) >= 0 && + assert(instructionId >= lastUpdatedInstructionId_ && + (lastUpdatedInstructionId_ = instructionId) >= 0 && "Update not called on branch instructions in program order"); // Retrieve the previous global history and branch direction prediction from @@ -126,11 +126,8 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Update the perceptron if the prediction was wrong, or the dot product's // magnitude was not greater than the training threshold if ((directionPrediction != isTaken) || - (abs(prevPout) < trainingThreshold_)) { + (static_cast(std::abs(prevPout)) < trainingThreshold_)) { int8_t t = (isTaken) ? 1 : -1; - if ((directionPrediction != taken) || - (static_cast(std::abs(Pout)) < trainingThreshold_)) { - int8_t t = (taken) ? 1 : -1; for (uint64_t i = 0; i < globalHistoryLength_; i++) { int8_t xi = diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index c3f5d61c06..fde0b7d309 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,7 +53,7 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); - BranchPrediction pred = branchPredictor_.predict( + [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && From f543387c9e932bf42f2ad2f1261453636229622e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:54:49 +0100 Subject: [PATCH 158/191] Hiding variables that are unused in Release behind ifndef clause --- src/include/simeng/branchpredictors/GenericPredictor.hh | 5 ++++- src/include/simeng/branchpredictors/PerceptronPredictor.hh | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 28f2ee5a81..9b9a859045 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -85,9 +85,12 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; + // This variable is used only in debug mode -- therefore hide behind ifdef +#ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; + uint64_t lastUpdatedInstructionId_ = 0; +#endif }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index d3392b4c90..305a12e80c 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -101,9 +101,12 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; + // This variable is used only in debug mode -- therefore hide behind ifdef +#ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ - [[maybe_unused]] uint64_t lastUpdatedInstructionId_ = 0; + uint64_t lastUpdatedInstructionId_ = 0; +#endif }; } // namespace simeng From 7cb9ce0ce60bbaeef1112a1cc57ef1c255a7d539 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:44:10 +0100 Subject: [PATCH 159/191] Adding to branch predictor docs --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 28ce96ddc8..b22a83de78 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -17,7 +17,7 @@ The usage of these parameters within a branch predictor's ``predict`` function i The ``update`` function is passed the branch outcome, the instruction address, and the branch type. From this information, any algorithms or branch structures may be updated. -The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the back of the ftq on ``predict``, and a single entry is removed from the front of the queue on ``update`` and from the back of the queue on ``flush``. +The state of the branch predictor when ``predict`` is called on a branch is stored in the ``ftq`` to be used by the ``update`` function. For instance, the perceptron predictor stores the globalHistory and confidence for each prediction, but future predictors may store alternative state. The ``ftq`` is a queue that has an entry for each in-flight branch. A single entry is added to the back of the ftq on ``predict``, and a single entry is removed from the front of the queue on ``update`` and from the back of the queue on ``flush``. Generic Predictor ----------------- From 499d66bae0489a6f8f19edf49856df3e657df488 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:48:36 +0100 Subject: [PATCH 160/191] Changing nomenclature --- docs/sphinx/developer/components/branchPred.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index b22a83de78..348541a345 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes as a bitmap, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. From 659bdd3739d5e335409c30aa9d004f4ba991d1e6 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:50:02 +0100 Subject: [PATCH 161/191] Adding to branch predictor lastUpdatedInstructionId_ comment --- src/include/simeng/branchpredictors/GenericPredictor.hh | 3 ++- src/include/simeng/branchpredictors/PerceptronPredictor.hh | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 9b9a859045..d91ae0571a 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -85,7 +85,8 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; - // This variable is used only in debug mode -- therefore hide behind ifdef + // This variable is used only in debug mode to prevent errors -- therefore + // hide behind ifdef #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 305a12e80c..5669cee043 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -101,7 +101,8 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; - // This variable is used only in debug mode -- therefore hide behind ifdef + // This variable is used only in debug mode to prevent errors -- therefore + // hide behind ifdef #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ From cdccbe8f65e7cd77d836335a786153bd82bf6d90 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:52:30 +0100 Subject: [PATCH 162/191] Adding comment re unused predict() call in the fetch unit --- src/lib/pipeline/FetchUnit.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index fde0b7d309..329ff53396 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -53,7 +53,10 @@ void FetchUnit::tick() { // Set prediction to recorded value during loop buffer filling if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); - [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( + // Calling predict() in order to log the branch in the branch + // predictor. However, we are reusing the prediction from the loop + // buffer so we do not use the return value from predict() + branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && From db4011afc016b31fd38510007fc5e57d9255e94c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:58:27 +0100 Subject: [PATCH 163/191] Moving lasyUpdatedInstructionId_ to BranchPredictor.hh --- src/include/simeng/branchpredictors/BranchPredictor.hh | 9 +++++++++ src/include/simeng/branchpredictors/GenericPredictor.hh | 8 -------- .../simeng/branchpredictors/PerceptronPredictor.hh | 8 -------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 3c0b66597a..ba0eb8bb8a 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -65,6 +65,15 @@ class BranchPredictor { * once, the exact order that the individual instructions within this block * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; + + + // This variable is used only in debug mode to prevent errors -- therefore + // hide behind ifdef +#ifndef NDEBUG + /** The Id of the last instruction that update was called on -- used to + * ensure that update is called in program order. */ + uint64_t lastUpdatedInstructionId_ = 0; +#endif }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index d91ae0571a..dd00526cf3 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -84,14 +84,6 @@ class GenericPredictor : public BranchPredictor { /** The size of the RAS. */ uint16_t rasSize_; - - // This variable is used only in debug mode to prevent errors -- therefore - // hide behind ifdef -#ifndef NDEBUG - /** The Id of the last instruction that update was called on -- used to - * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId_ = 0; -#endif }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 5669cee043..bdde169451 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -100,14 +100,6 @@ class PerceptronPredictor : public BranchPredictor { /** The size of the RAS. */ uint64_t rasSize_; - - // This variable is used only in debug mode to prevent errors -- therefore - // hide behind ifdef -#ifndef NDEBUG - /** The Id of the last instruction that update was called on -- used to - * ensure that update is called in program order. */ - uint64_t lastUpdatedInstructionId_ = 0; -#endif }; } // namespace simeng From b14427eb4ee058a2dec2840727f35a78eb5395bb Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:05:55 +0100 Subject: [PATCH 164/191] clang format --- src/include/simeng/branchpredictors/BranchPredictor.hh | 1 - src/lib/pipeline/FetchUnit.cc | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index ba0eb8bb8a..6b7d58f9c5 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -66,7 +66,6 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; - // This variable is used only in debug mode to prevent errors -- therefore // hide behind ifdef #ifndef NDEBUG diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 329ff53396..b421060d20 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -56,9 +56,9 @@ void FetchUnit::tick() { // Calling predict() in order to log the branch in the branch // predictor. However, we are reusing the prediction from the loop // buffer so we do not use the return value from predict() - branchPredictor_.predict( - macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset()); + branchPredictor_.predict(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && "New prediction differs from loop buffer prediction"); branchesFetched_++; From 307b5f027cc4af7ad22c2d77e7ef22cf08bb6971 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:44:53 +0100 Subject: [PATCH 165/191] Adding more detail to idndef comment in BranchPredictor.hh --- src/include/simeng/branchpredictors/BranchPredictor.hh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 6b7d58f9c5..77af36eb3b 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -66,8 +66,10 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; - // This variable is used only in debug mode to prevent errors -- therefore - // hide behind ifdef + // This variable is used only in debug mode. Hiding behind ifdef to avoid + // compiler errors. Clang throws a warning (which becomes an error) for an + // unused variable. If the [[maybe_unused]] flag is added to avoid this, + // then gcc throws an error because it does heed this flag. #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ From 480e7035713ae16c0c499105f34e3c6fbd792c0c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:05:35 +0100 Subject: [PATCH 166/191] Updating comments in FetchUnit.cc --- src/lib/pipeline/FetchUnit.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index b421060d20..064b2161ed 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -55,10 +55,11 @@ void FetchUnit::tick() { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Calling predict() in order to log the branch in the branch // predictor. However, we are reusing the prediction from the loop - // buffer so we do not use the return value from predict() - branchPredictor_.predict(macroOp[0]->getInstructionAddress(), - macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset()); + // buffer so we do not use the return value from predict() except for + // in an assert + [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( + macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset()); assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && "New prediction differs from loop buffer prediction"); branchesFetched_++; From d73ed83a91892242d6e5dbcbdcbfba96a6d20ac3 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:34:04 +0100 Subject: [PATCH 167/191] Adding to BP documentation --- docs/sphinx/developer/components/branchPred.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index 348541a345..c15e456bb1 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-64. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. From f2302ad287c8793ecc07c6754da554cb06e9cd6d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:55:33 +0100 Subject: [PATCH 168/191] Adding to comments to address PR comments --- src/include/simeng/branchpredictors/BranchPredictor.hh | 4 ++-- src/lib/pipeline/FetchUnit.cc | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 77af36eb3b..4bcbbec3fa 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -68,8 +68,8 @@ class BranchPredictor { // This variable is used only in debug mode. Hiding behind ifdef to avoid // compiler errors. Clang throws a warning (which becomes an error) for an - // unused variable. If the [[maybe_unused]] flag is added to avoid this, - // then gcc throws an error because it does heed this flag. + // unused variable. If the [[maybe_unused]] attribute is added to avoid this, + // then gcc throws an error because it ignores this attribute. #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 064b2161ed..3a46a6375c 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -54,9 +54,9 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Calling predict() in order to log the branch in the branch - // predictor. However, we are reusing the prediction from the loop - // buffer so we do not use the return value from predict() except for - // in an assert + // predictor (which tracks the in flight-brnaches in the ftq). However, + // we are reusing the prediction from the loop buffer so we do not + // use the return value from predict() except for in an assert [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); From 5c8173a518c85bc17e0a91b99d039de6107627a1 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:47:34 +0100 Subject: [PATCH 169/191] Adjusting comment explaining ifdef in BranchPredictor.hh --- .../simeng/branchpredictors/BranchPredictor.hh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 4bcbbec3fa..fceca018e2 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -66,10 +66,13 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; - // This variable is used only in debug mode. Hiding behind ifdef to avoid - // compiler errors. Clang throws a warning (which becomes an error) for an - // unused variable. If the [[maybe_unused]] attribute is added to avoid this, - // then gcc throws an error because it ignores this attribute. + /** lastUpdatedInstructionId_ is used only in debug mode. Clang throws a + * warning (which becomes an error with our cmake flags) for unused + * variables. If the [[maybe_unused]] attribute is added to avoid this, + * then gcc throws a warning (which becomes an error) because it ignores + * this attribute. Therefore, to avoid the above catch 22, this variable is + * hidden behind an ifdef such that it is declared only in debug mode; when + * it is used. */ #ifndef NDEBUG /** The Id of the last instruction that update was called on -- used to * ensure that update is called in program order. */ From 921aee0968afbca0c93e1997916b0e59abb9fe50 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:52:01 +0100 Subject: [PATCH 170/191] Updating comment regarding maybe_unused attribute in FetchUnit.cc --- src/lib/pipeline/FetchUnit.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 3a46a6375c..113739246c 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -54,9 +54,12 @@ void FetchUnit::tick() { if (macroOp[0]->isBranch()) { macroOp[0]->setBranchPrediction(loopBuffer_.front().prediction); // Calling predict() in order to log the branch in the branch - // predictor (which tracks the in flight-brnaches in the ftq). However, - // we are reusing the prediction from the loop buffer so we do not - // use the return value from predict() except for in an assert + // predictor. The branch needs to be logged in the branch predictor + // so that the branch predictor has the information needed to update + // itself when the branch instruction is retired. However, we are + // reusing the prediction from the loop buffer, thus we do not + // use the return value from predict() except for in an assert. + // Therefore, it is given the [[maybe_unused]] attribute. [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); From 36c14cb5112234cc75747461365da006ade2b000 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:42:13 +0100 Subject: [PATCH 171/191] Getting rid of superfluous assert in FetchUnit.cc -- the BP works regardless of the prediction being the same as the loop buffers recycled prediction --- src/lib/pipeline/FetchUnit.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 113739246c..eac683c98e 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -63,8 +63,6 @@ void FetchUnit::tick() { [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), macroOp[0]->getKnownOffset()); - assert(pred.isTaken == loopBuffer_.front().prediction.isTaken && - "New prediction differs from loop buffer prediction"); branchesFetched_++; } From 5dfbd81040fbd8f974f98afc2b09bd2aa4500c06 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:37:23 +0100 Subject: [PATCH 172/191] Making further changes to comments --- docs/sphinx/developer/components/branchPred.rst | 4 ++-- src/lib/config/ModelConfig.cc | 2 +- src/lib/pipeline/FetchUnit.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sphinx/developer/components/branchPred.rst b/docs/sphinx/developer/components/branchPred.rst index c15e456bb1..6a03c85129 100644 --- a/docs/sphinx/developer/components/branchPred.rst +++ b/docs/sphinx/developer/components/branchPred.rst @@ -25,7 +25,7 @@ Generic Predictor The algorithm(s) held within a ``BranchPredictor`` class instance can be model-specific, however, SimEng provides a ``GenericPredictor`` which contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-64. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-32. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with an n-bit saturating counter for an associated direction. The indexing of this structure uses the lower bits of an instruction address XOR'ed with the current global branch history value. @@ -43,7 +43,7 @@ Perceptron Predictor The ``PerceptronPredictor`` has the same overall structure as the ``GenericPredictor`` but replaces the saturating counter as a means for direction prediction with a perceptron. The ``PerceptronPredictor`` contains the following logic. Global History - For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned int, with the least-significant bit being the most recent. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. + For indexing relevant prediction structures, a global history can be utilised. The global history value stores the n most recent branch direction outcomes in an unsigned integer, with the least-significant bit being the most recent branch direction. The global history is speculatively updated on ``predict``, and is corrected if needed on ``update`` and ``flush``. To facilitate this speculative updating, and rolling-back on correction, for a global history of n the branch predictor keeps track of the 2n most recent branch outcomes. Valid values for Global History are 1-32. Branch Target Buffer (BTB) For each entry, the BTB stores the most recent target along with a perceptron for an associated direction. The indexing of this structure uses the lower, non-zero bits of an instruction address XOR'ed with the current global branch history value. diff --git a/src/lib/config/ModelConfig.cc b/src/lib/config/ModelConfig.cc index 049c24d04a..6d6152ced4 100644 --- a/src/lib/config/ModelConfig.cc +++ b/src/lib/config/ModelConfig.cc @@ -514,7 +514,7 @@ void ModelConfig::setExpectations(bool isDefault) { expectations_["Branch-Predictor"].addChild( ExpectationNode::createExpectation(8, "Global-History-Length")); expectations_["Branch-Predictor"]["Global-History-Length"] - .setValueBounds(1, UINT16_MAX); + .setValueBounds(1, 32); expectations_["Branch-Predictor"].addChild( ExpectationNode::createExpectation(8, "RAS-entries")); diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index eac683c98e..b769f08190 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -58,7 +58,7 @@ void FetchUnit::tick() { // so that the branch predictor has the information needed to update // itself when the branch instruction is retired. However, we are // reusing the prediction from the loop buffer, thus we do not - // use the return value from predict() except for in an assert. + // use the return value from predict(). // Therefore, it is given the [[maybe_unused]] attribute. [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), From 9284920da9ab1e37185c50a46cac95c2ae46a436 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:45:47 +0100 Subject: [PATCH 173/191] Shortening comments --- src/lib/pipeline/FetchUnit.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index b769f08190..9ae6aa1d3a 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -59,10 +59,9 @@ void FetchUnit::tick() { // itself when the branch instruction is retired. However, we are // reusing the prediction from the loop buffer, thus we do not // use the return value from predict(). - // Therefore, it is given the [[maybe_unused]] attribute. - [[maybe_unused]] BranchPrediction pred = branchPredictor_.predict( - macroOp[0]->getInstructionAddress(), macroOp[0]->getBranchType(), - macroOp[0]->getKnownOffset()); + branchPredictor_.predict(macroOp[0]->getInstructionAddress(), + macroOp[0]->getBranchType(), + macroOp[0]->getKnownOffset()); branchesFetched_++; } From 3d4acc2640e104f963d897694eb30bea601121ff Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:53:14 +0100 Subject: [PATCH 174/191] Adding branches retired statistic, and specifying how it is calculated in the docs --- docs/sphinx/user/running_simeng.rst | 3 ++- src/include/simeng/pipeline/ReorderBuffer.hh | 6 ++++++ src/lib/models/outoforder/Core.cc | 4 +++- src/lib/pipeline/ReorderBuffer.cc | 8 +++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/user/running_simeng.rst b/docs/sphinx/user/running_simeng.rst index 92a9682032..0a97fc50fe 100644 --- a/docs/sphinx/user/running_simeng.rst +++ b/docs/sphinx/user/running_simeng.rst @@ -26,7 +26,8 @@ Exit Clause The reason why the simulation has halted. Most commonly this is due to the invoking of the ``exit()`` system call by the workload under simulation. Statistics - A selection of simulation statistics describing the emergent simulated PMU-style hardware events. + A selection of simulation statistics describing the emergent simulated PMU-style hardware events. With respect to branch statistics, the misprediction rate +is calculated as branches mispredicted / branches retired. All non-workload outputs from SimEng are prefixed with a tag of the format ``[SimEng:Object]`` (e.g. ``[SimEng:ExceptionHandler]``). If the output came from the root of the framework, the ``Object`` field is omitted. diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index 64a32ce78b..df926eeca0 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -88,6 +88,9 @@ class ReorderBuffer { /** Retrieve the number of branch mispredictions. */ uint64_t getBranchMispredictedCount() const; + /** Retrieve the number of retired brancehs. */ + uint64_t getRetiredBranchesCount() const; + private: /** A reference to the register alias table. */ RegisterAliasTable& rat_; @@ -150,6 +153,9 @@ class ReorderBuffer { /** The number of branch mispredictions that were observed. */ uint64_t branchMispredicts_ = 0; + + /** The number of retired branch instructions */ + uint64_t retiredBranches_ = 0; }; } // namespace pipeline diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 459cb552e9..9db41eed15 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -225,10 +225,11 @@ std::map Core::getStats() const { auto portBusyStalls = dispatchIssueUnit_.getPortBusyStalls(); uint64_t totalBranchesFetched = fetchUnit_.getBranchFetchedCount(); + uint64_t totalBranchesRetired = reorderBuffer_.getRetiredBranchesCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesFetched); + static_cast(totalBranchesRetired); std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; @@ -247,6 +248,7 @@ std::map Core::getStats() const { {"issue.backendStalls", std::to_string(backendStalls)}, {"issue.portBusyStalls", std::to_string(portBusyStalls)}, {"branch.fetched", std::to_string(totalBranchesFetched)}, + {"branch.retired", std::to_string(totalBranchesRetired)}, {"branch.mispredict", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}, {"lsq.loadViolations", diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index cf5c2c52bb..5f5e042d48 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -159,7 +159,8 @@ unsigned int ReorderBuffer::commit(uint64_t maxCommitSize) { predictor_.update(uop->getInstructionAddress(), uop->wasBranchTaken(), uop->getBranchAddress(), uop->getBranchType(), uop->getInstructionId()); - // Update the branch misprediction counter + // Update the branches retired and mispredicted counters + retiredBranches_++; if (uop->wasBranchMispredicted()) branchMispredicts_++; } @@ -190,6 +191,7 @@ void ReorderBuffer::flush(uint64_t afterInsnId) { // If the instruction is a branch, supply address to branch flushing logic if (uop->isBranch()) { predictor_.flush(uop->getInstructionAddress()); + } buffer_.pop_back(); } @@ -216,9 +218,13 @@ uint64_t ReorderBuffer::getInstructionsCommittedCount() const { uint64_t ReorderBuffer::getViolatingLoadsCount() const { return loadViolations_; } + uint64_t ReorderBuffer::getBranchMispredictedCount() const { return branchMispredicts_; } +uint64_t ReorderBuffer::getRetiredBranchesCount() const { + return retiredBranches_; +} } // namespace pipeline } // namespace simeng From a8d2d5d95a3450ead8403a9b5d9c570690454fbe Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:14:45 +0100 Subject: [PATCH 175/191] clang format --- src/lib/pipeline/ReorderBuffer.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/pipeline/ReorderBuffer.cc b/src/lib/pipeline/ReorderBuffer.cc index 5f5e042d48..e72e6e79dc 100644 --- a/src/lib/pipeline/ReorderBuffer.cc +++ b/src/lib/pipeline/ReorderBuffer.cc @@ -191,7 +191,6 @@ void ReorderBuffer::flush(uint64_t afterInsnId) { // If the instruction is a branch, supply address to branch flushing logic if (uop->isBranch()) { predictor_.flush(uop->getInstructionAddress()); - } buffer_.pop_back(); } From 327a720db8297dd323887b95ffc114c8cee54929 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:41:13 +0100 Subject: [PATCH 176/191] Rebasing --- src/lib/models/outoforder/Core.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 9db41eed15..59774eeaaf 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -249,7 +249,7 @@ std::map Core::getStats() const { {"issue.portBusyStalls", std::to_string(portBusyStalls)}, {"branch.fetched", std::to_string(totalBranchesFetched)}, {"branch.retired", std::to_string(totalBranchesRetired)}, - {"branch.mispredict", std::to_string(totalBranchMispredicts)}, + {"branch.mispredicted", std::to_string(totalBranchMispredicts)}, {"branch.missrate", branchMissRateStr.str()}, {"lsq.loadViolations", std::to_string(reorderBuffer_.getViolatingLoadsCount())}}; From f3c721b92fe84e0eb04ec639818f6d20a174394e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:09:58 +0100 Subject: [PATCH 177/191] Rebasing --- src/lib/pipeline/FetchUnit.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/pipeline/FetchUnit.cc b/src/lib/pipeline/FetchUnit.cc index 9ae6aa1d3a..ea59f1a071 100644 --- a/src/lib/pipeline/FetchUnit.cc +++ b/src/lib/pipeline/FetchUnit.cc @@ -190,7 +190,8 @@ void FetchUnit::tick() { // loopBoundaryAddress_ has been fetched whilst loop buffer is waiting, // start filling Loop Buffer if the branch predictor tells us to // reenter the detected loop - if (macroOp[0]->isBranch() && !macroOp[0]->getBranchPrediction().taken) { + if (macroOp[0]->isBranch() && + !macroOp[0]->getBranchPrediction().isTaken) { // If branch is not taken then we aren't re-entering the detected // loop, therefore Loop Buffer stays idle loopBufferState_ = LoopBufferState::IDLE; From 28a8e30ea1e1783f94d9236abb946d4e3eba8031 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:42:40 +0100 Subject: [PATCH 178/191] Changing CI check test to differentiate instructions retired and branches retired --- .jenkins/build_test_run.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index 22e48655c9..d92c5b8369 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -70,8 +70,10 @@ run () { echo "Simulation with configuration file argument:" cat run echo "" - compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" - compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "8612" "simulated cycles" + compare_outputs "$(grep " retired:" run | rev | cut -d ' ' -f1 | rev)" + "6724" "retired instructions" + compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" + "8612" "simulated cycles" echo "" } From 7a71430ba4a2a48994569a95026012d07efb4e2d Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:57:32 +0100 Subject: [PATCH 179/191] Changing CI check test to differentiate instructions retired and branches retired --- .jenkins/build_test_run.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index d92c5b8369..a9ad60db61 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -62,18 +62,16 @@ run () { echo "Simulation without configuration file argument:" cat run echo "" - compare_outputs "$(grep "retired:" run | rev | cut -d ' ' -f1 | rev)" "6721" "retired instructions" - compare_outputs "$(grep "cycles:" run | rev | cut -d ' ' -f1 | rev)" "6721" "simulated cycles" + compare_outputs "$(grep " retired:" run | rev | cut -d ' ' -f1 | rev)" "6721" "retired instructions" + compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" "6721" "simulated cycles" echo "" ./bin/simeng "$SIMENG_TOP"/configs/tx2.yaml > run echo "Simulation with configuration file argument:" cat run echo "" - compare_outputs "$(grep " retired:" run | rev | cut -d ' ' -f1 | rev)" - "6724" "retired instructions" - compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" - "8612" "simulated cycles" + compare_outputs "$(grep " retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" + compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" "8612" "simulated cycles" echo "" } From 0159790fcfceb27e02dc79adfbf5d6aa9f1a9cb2 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:13:05 +0100 Subject: [PATCH 180/191] Changing expected number of simulated cycles --- .jenkins/build_test_run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index a9ad60db61..dcc3e78a6e 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -71,7 +71,7 @@ run () { cat run echo "" compare_outputs "$(grep " retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" - compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" "8612" "simulated cycles" + compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" "7496" "simulated cycles" echo "" } From 446385b6154e25f3082438eb3b5390a5b15f30bb Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:53:23 +0100 Subject: [PATCH 181/191] Updating buffer flush logic --- src/include/simeng/Instruction.hh | 2 +- .../branchpredictors/BranchPrediction.hh | 43 ++++++++++ .../branchpredictors/BranchPredictor.hh | 82 ++++++++++--------- .../branchpredictors/GenericPredictor.hh | 2 +- .../branchpredictors/PerceptronPredictor.hh | 2 +- src/include/simeng/pipeline/PipelineBuffer.hh | 32 -------- src/include/simeng/pipeline/ReorderBuffer.hh | 1 + src/lib/models/outoforder/Core.cc | 14 ++-- test/unit/GenericPredictorTest.cc | 6 +- 9 files changed, 102 insertions(+), 82 deletions(-) create mode 100644 src/include/simeng/branchpredictors/BranchPrediction.hh diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index 6bdeb1e401..b5a4e33e3b 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -5,7 +5,7 @@ #include "capstone/capstone.h" #include "simeng/Register.hh" #include "simeng/RegisterValue.hh" -#include "simeng/branchpredictors/BranchPredictor.hh" +#include "simeng/branchpredictors/BranchPrediction.hh" #include "simeng/memory/MemoryInterface.hh" #include "simeng/span.hh" diff --git a/src/include/simeng/branchpredictors/BranchPrediction.hh b/src/include/simeng/branchpredictors/BranchPrediction.hh new file mode 100644 index 0000000000..243dffcaa5 --- /dev/null +++ b/src/include/simeng/branchpredictors/BranchPrediction.hh @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace simeng { + +/** The types of branches recognised. */ +enum class BranchType { + Conditional = 0, + LoopClosing, + Return, + SubroutineCall, + Unconditional, + Unknown +}; + +/** A branch result prediction for an instruction. */ +struct BranchPrediction { + /** Whether the branch will be taken. */ + bool isTaken; + + /** The branch instruction's target address. If `isTaken == false`, the value + * will be ignored. */ + uint64_t target; + + /** Check for equality of two branch predictions . */ + bool operator==(const BranchPrediction& other) { + if ((isTaken == other.isTaken) && (target == other.target)) + return true; + else + return false; + } + + /** Check for inequality of two branch predictions . */ + bool operator!=(const BranchPrediction& other) { + if ((isTaken != other.isTaken) || (target != other.target)) + return true; + else + return false; + } +}; + +} // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index fceca018e2..82f537b86a 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -3,43 +3,11 @@ #include #include -namespace simeng { - -/** The types of branches recognised. */ -enum class BranchType { - Conditional = 0, - LoopClosing, - Return, - SubroutineCall, - Unconditional, - Unknown -}; - -/** A branch result prediction for an instruction. */ -struct BranchPrediction { - /** Whether the branch will be taken. */ - bool isTaken; +#include "simeng/Instruction.hh" +#include "simeng/branchpredictors/BranchPrediction.hh" +#include "simeng/pipeline/PipelineBuffer.hh" - /** The branch instruction's target address. If `isTaken == false`, the value - * will be ignored. */ - uint64_t target; - - /** Check for equality of two branch predictions . */ - bool operator==(const BranchPrediction& other) { - if ((isTaken == other.isTaken) && (target == other.target)) - return true; - else - return false; - } - - /** Check for inequality of two branch predictions . */ - bool operator!=(const BranchPrediction& other) { - if ((isTaken != other.isTaken) || (target != other.target)) - return true; - else - return false; - } -}; +namespace simeng { /** An abstract branch predictor interface. */ class BranchPredictor { @@ -50,7 +18,7 @@ class BranchPredictor { * branch type, and a known branch offset; defaults to 0 meaning offset is not * known. Returns a branch direction and branch target address. */ virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) = 0; + int64_t knownOffset = 0) = 0; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -66,6 +34,46 @@ class BranchPredictor { * are flushed does not matter so long as they are all flushed). */ virtual void flush(uint64_t address) = 0; + /** + * Overloaded function for flushing branch instructions from a pipeline. + * Accepts pipelines of either microops or macroops. Iterates over the + * entries of the pipeline and, if they are a branch instruction, flushes + * them. + */ + void flushBuffer( + pipeline::PipelineBuffer> buffer) { + for (size_t slot = 0; slot < buffer.getWidth(); slot++) { + auto& uop = buffer.getTailSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + flush(uop->getInstructionAddress()); + } + + uop = buffer.getHeadSlots()[slot]; + if (uop != nullptr && uop->isBranch()) { + flush(uop->getInstructionAddress()); + } + } + } + void flushBuffer( + pipeline::PipelineBuffer>> + buffer) { + for (size_t slot = 0; slot < buffer.getWidth(); slot++) { + auto& macroOp = buffer.getTailSlots()[slot]; + for (size_t uop = 0; uop < macroOp.size(); uop++) { + if (macroOp[uop]->isBranch()) { + flush(macroOp[uop]->getInstructionAddress()); + } + } + + macroOp = buffer.getHeadSlots()[slot]; + for (size_t uop = 0; uop < macroOp.size(); uop++) { + if (macroOp[uop]->isBranch()) { + flush(macroOp[uop]->getInstructionAddress()); + } + } + } + } + /** lastUpdatedInstructionId_ is used only in debug mode. Clang throws a * warning (which becomes an error with our cmake flags) for unused * variables. If the [[maybe_unused]] attribute is added to avoid this, diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index dd00526cf3..68ba7bd755 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -31,7 +31,7 @@ class GenericPredictor : public BranchPredictor { * branch type, and a known branch offset; defaults to 0 meaning offset is not * known. Returns a branch direction and branch target address. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) override; + int64_t knownOffset) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index bdde169451..d3fc2e92da 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -34,7 +34,7 @@ class PerceptronPredictor : public BranchPredictor { * branch type, and a known branch offset; defaults to 0 meaning offset is not * known. Returns a branch direction and branch target address. */ BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) override; + int64_t knownOffset) override; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on diff --git a/src/include/simeng/pipeline/PipelineBuffer.hh b/src/include/simeng/pipeline/PipelineBuffer.hh index bd7c565735..6e128ae684 100644 --- a/src/include/simeng/pipeline/PipelineBuffer.hh +++ b/src/include/simeng/pipeline/PipelineBuffer.hh @@ -4,8 +4,6 @@ #include #include -#include "simeng/branchpredictors/BranchPredictor.hh" - namespace simeng { namespace pipeline { @@ -75,36 +73,6 @@ class PipelineBuffer { /** Get the width of the buffer slots. */ uint16_t getWidth() const { return width; } - /** Flush branches in the buffer from the branch predictor, where the - * buffer contains micro-ops */ - void flushBranchMicroOps(BranchPredictor& branchPredictor) { - for (size_t slot = 0; slot < width; slot++) { - auto& uop = getTailSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - branchPredictor.flush(uop->getInstructionAddress()); - } - uop = getHeadSlots()[slot]; - if (uop != nullptr && uop->isBranch()) { - branchPredictor.flush(uop->getInstructionAddress()); - } - } - } - - /** Flush branches in the buffer from the branch predictor, where the - * buffer contains macro-ops */ - void flushBranchMacroOps(BranchPredictor& branchPredictor) { - for (size_t slot = 0; slot < width; slot++) { - auto& macroOp = getTailSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - branchPredictor.flush(macroOp[0]->getInstructionAddress()); - } - macroOp = getHeadSlots()[slot]; - if (!macroOp.empty() && macroOp[0]->isBranch()) { - branchPredictor.flush(macroOp[0]->getInstructionAddress()); - } - } - } - private: /** The width of each row of slots. */ uint16_t width; diff --git a/src/include/simeng/pipeline/ReorderBuffer.hh b/src/include/simeng/pipeline/ReorderBuffer.hh index df926eeca0..2e6e68e37b 100644 --- a/src/include/simeng/pipeline/ReorderBuffer.hh +++ b/src/include/simeng/pipeline/ReorderBuffer.hh @@ -4,6 +4,7 @@ #include #include "simeng/Instruction.hh" +#include "simeng/branchpredictors/BranchPredictor.hh" #include "simeng/pipeline/LoadStoreQueue.hh" #include "simeng/pipeline/RegisterAliasTable.hh" diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 59774eeaaf..1c3a4be2b0 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -228,8 +228,8 @@ std::map Core::getStats() const { uint64_t totalBranchesRetired = reorderBuffer_.getRetiredBranchesCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); - auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / - static_cast(totalBranchesRetired); + auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / + static_cast(totalBranchesRetired); std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; @@ -263,11 +263,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check for branch instructions in buffer, and flush them from the BP. // Then empty the buffers - fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); + branchPredictor_.flushBuffer(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - decodeToRenameBuffer_.flushBranchMicroOps(branchPredictor_); + branchPredictor_.flushBuffer(decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -351,11 +351,11 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); + branchPredictor_.flushBuffer(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - decodeToRenameBuffer_.flushBranchMicroOps(branchPredictor_); + branchPredictor_.flushBuffer(decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -383,7 +383,7 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - fetchToDecodeBuffer_.flushBranchMacroOps(branchPredictor_); + branchPredictor_.flushBuffer(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); diff --git a/test/unit/GenericPredictorTest.cc b/test/unit/GenericPredictorTest.cc index 0c627f98f7..c7d6011c29 100644 --- a/test/unit/GenericPredictorTest.cc +++ b/test/unit/GenericPredictorTest.cc @@ -263,9 +263,9 @@ TEST_F(GenericPredictorTest, flush) { // Test that update correctly corrects the speculatively updated global history TEST_F(GenericPredictorTest, speculativeGlobalHistory) { simeng::config::SimInfo::addToConfig( - "{Branch-Predictor: {BTB-Tag-Bits: 6, Saturating-Count-Bits: 2, " - "Global-History-Length: 6, RAS-entries: 10, Fallback-Static-Predictor: " - "Always-Taken}}"); + "{Branch-Predictor: {Type: Generic, BTB-Tag-Bits: 6, " + "Saturating-Count-Bits: 2, Global-History-Length: 6, RAS-entries: 10, " + "Fallback-Static-Predictor: Always-Taken}}"); auto predictor = simeng::GenericPredictor(); BranchPrediction pred; From 582da295ab9ac652d73a5250ef59aba8a75daa4c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:40:13 +0100 Subject: [PATCH 182/191] Attending to comments on PR --- .../branchpredictors/BranchPredictor.hh | 20 ++++++++++++------- src/lib/models/outoforder/Core.cc | 10 +++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 82f537b86a..655f2924ac 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -35,12 +35,12 @@ class BranchPredictor { virtual void flush(uint64_t address) = 0; /** - * Overloaded function for flushing branch instructions from a pipeline. - * Accepts pipelines of either microops or macroops. Iterates over the - * entries of the pipeline and, if they are a branch instruction, flushes - * them. + * Overloaded function for flushing branch instructions from a + * PipelineBuffer. Accepts PipelineBuffers of microops. + * Iterates over the entries of the PipelineBuffer and, if they are a + * branch instruction, flushes them. */ - void flushBuffer( + void flushBranchesInBufferFromSelf( pipeline::PipelineBuffer> buffer) { for (size_t slot = 0; slot < buffer.getWidth(); slot++) { auto& uop = buffer.getTailSlots()[slot]; @@ -54,7 +54,14 @@ class BranchPredictor { } } } - void flushBuffer( + + /** + * Overloaded function for flushing branch instructions from a + * PipelineBuffer. Accepts PipelineBuffers macroops. + * Iterates over the entries of the PipelineBuffer and, if they are a + * branch instruction, flushes them. + */ + void flushBranchesInBufferFromSelf( pipeline::PipelineBuffer>> buffer) { for (size_t slot = 0; slot < buffer.getWidth(); slot++) { @@ -64,7 +71,6 @@ class BranchPredictor { flush(macroOp[uop]->getInstructionAddress()); } } - macroOp = buffer.getHeadSlots()[slot]; for (size_t uop = 0; uop < macroOp.size(); uop++) { if (macroOp[uop]->isBranch()) { diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 1c3a4be2b0..1c518d2e63 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -263,11 +263,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check for branch instructions in buffer, and flush them from the BP. // Then empty the buffers - branchPredictor_.flushBuffer(fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - branchPredictor_.flushBuffer(decodeToRenameBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -351,11 +351,11 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - branchPredictor_.flushBuffer(fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - branchPredictor_.flushBuffer(decodeToRenameBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -383,7 +383,7 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - branchPredictor_.flushBuffer(fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); From cf4137f6f33c0d25fc7185a2f280d6345cded84c Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:32:28 +0100 Subject: [PATCH 183/191] Making predict a wrapper function --- .../AlwaysNotTakenPredictor.hh | 11 +- .../branchpredictors/BranchPredictor.hh | 23 +++- .../branchpredictors/GenericPredictor.hh | 12 +- .../branchpredictors/PerceptronPredictor.hh | 12 +- .../AlwaysNotTakenPredictor.cc | 10 +- src/lib/branchpredictors/GenericPredictor.cc | 101 +++++++------- .../branchpredictors/PerceptronPredictor.cc | 129 +++++++++--------- test/unit/MockBranchPredictor.hh | 5 + 8 files changed, 161 insertions(+), 142 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index ab186223b1..f2722815fe 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -8,11 +8,6 @@ namespace simeng { * taken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: - /** Generate a branch prediction for the specified instruction address; will - * always predict not taken. */ - BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) override; - /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on * branches in program order. To check this, instructionId is also passed @@ -23,6 +18,12 @@ class AlwaysNotTakenPredictor : public BranchPredictor { /** Provide flush logic for branch prediction scheme. As there's no flush * logic for an always taken predictor, this does nothing. */ void flush(uint64_t address) override; + + private: + /** Generate a branch prediction for the specified instruction address; will + * always predict not taken. */ + BranchPrediction makePrediction(uint64_t address, BranchType type, + int64_t knownOffset) override; }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 655f2924ac..b7a9a6ff34 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -14,11 +14,16 @@ class BranchPredictor { public: virtual ~BranchPredictor(){}; - /** Generate a branch prediction for the supplied instruction address, a - * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ + /** + * Wrapper function to provide default knownOffset to makePrediction, if + * needed. This is needed to avoid having to provide default values for + * knownOffset in each child class, and the risks associated with + * this interplay between default arguments and inheritance. + */ virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) = 0; + int64_t knownOffset = 0) { + return makePrediction(address, type, knownOffset); + } /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -36,7 +41,7 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts PipelineBuffers of microops. + * PipelineBuffer. Accepts PipelineBuffers of microOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ @@ -57,7 +62,7 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts PipelineBuffers macroops. + * PipelineBuffer. Accepts PipelineBuffers macroOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ @@ -92,6 +97,12 @@ class BranchPredictor { * ensure that update is called in program order. */ uint64_t lastUpdatedInstructionId_ = 0; #endif + private: + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset. Returns a branch direction and + * branch target address. */ + virtual BranchPrediction makePrediction(uint64_t address, BranchType type, + int64_t knownOffset) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index 68ba7bd755..e4353aafda 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -27,12 +27,6 @@ class GenericPredictor : public BranchPredictor { GenericPredictor(ryml::ConstNodeRef config = config::SimInfo::getConfig()); ~GenericPredictor(); - /** Generate a branch prediction for the supplied instruction address, a - * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ - BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) override; - /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on * branches in program order. To check this, instructionId is also passed @@ -48,6 +42,12 @@ class GenericPredictor : public BranchPredictor { void flush(uint64_t address) override; private: + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset. Returns a branch direction and + * branch target address. */ + BranchPrediction makePrediction(uint64_t address, BranchType type, + int64_t knownOffset) override; + /** The bitlength of the BTB index; BTB will have 2^bits entries. */ uint8_t btbBits_; diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index d3fc2e92da..90efe6dc00 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -30,12 +30,6 @@ class PerceptronPredictor : public BranchPredictor { PerceptronPredictor(ryml::ConstNodeRef config = config::SimInfo::getConfig()); ~PerceptronPredictor(); - /** Generate a branch prediction for the supplied instruction address, a - * branch type, and a known branch offset; defaults to 0 meaning offset is not - * known. Returns a branch direction and branch target address. */ - BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset) override; - /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on * branches in program order. To check this, instructionId is also passed @@ -51,6 +45,12 @@ class PerceptronPredictor : public BranchPredictor { void flush(uint64_t address) override; private: + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset. Returns a branch direction and + * branch target address. */ + BranchPrediction makePrediction(uint64_t address, BranchType type, + int64_t knownOffset) override; + /** Returns the dot product of a perceptron and a history vector. Used to * determine a direction prediction */ int64_t getDotProduct(const std::vector& perceptron, diff --git a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index bfe342cce5..15dcb749eb 100644 --- a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -2,15 +2,15 @@ namespace simeng { -BranchPrediction AlwaysNotTakenPredictor::predict( - [[maybe_unused]] uint64_t address, BranchType type, int64_t knownOffset) { - return {false, 0}; -} - void AlwaysNotTakenPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type, uint64_t instructionId) {} void AlwaysNotTakenPredictor::flush(uint64_t address) {} +BranchPrediction AlwaysNotTakenPredictor::makePrediction( + [[maybe_unused]] uint64_t address, BranchType type, int64_t knownOffset) { + return {false, 0}; +} + } // namespace simeng diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index a79289a62c..ba2d377f45 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -37,56 +37,6 @@ GenericPredictor::~GenericPredictor() { ftq_.clear(); } -BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset) { - // Get index via an XOR hash between the global history and the instruction - // address. This hash is then ANDed to keep it within bounds of the btb. - // The address is shifted to remove the two least-significant bits as these - // are always 0 in an ISA with 4-byte aligned instructions. - uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - - // Get prediction from BTB - bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); - uint64_t target = - (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; - BranchPrediction prediction = {direction, target}; - - // Amend prediction based on branch type - if (type == BranchType::Unconditional) { - prediction.isTaken = true; - } else if (type == BranchType::Return) { - prediction.isTaken = true; - // Return branches can use the RAS if an entry is available - if (ras_.size() > 0) { - prediction.target = ras_.back(); - // Record top of RAS used for target prediction - rasHistory_[address] = ras_.back(); - ras_.pop_back(); - } - } else if (type == BranchType::SubroutineCall) { - prediction.isTaken = true; - // Subroutine call branches must push their associated return address to RAS - if (ras_.size() >= rasSize_) { - ras_.pop_front(); - } - ras_.push_back(address + 4); - // Record that this address is a branch-and-link instruction - rasHistory_[address] = 0; - } else if (type == BranchType::Conditional) { - if (!prediction.isTaken) prediction.target = address + 4; - } - - // Store the hashed index for correct hashing in update() - ftq_.emplace_back(prediction.isTaken, hashedIndex); - - // Speculatively update the global history - globalHistory_ = - ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; - - return prediction; -} - void GenericPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type, uint64_t instructionId) { @@ -153,4 +103,55 @@ void GenericPredictor::flush(uint64_t address) { // Roll back global history globalHistory_ >>= 1; } + +BranchPrediction GenericPredictor::makePrediction(uint64_t address, + BranchType type, + int64_t knownOffset) { + // Get index via an XOR hash between the global history and the instruction + // address. This hash is then ANDed to keep it within bounds of the btb. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in an ISA with 4-byte aligned instructions. + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + + // Get prediction from BTB + bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); + uint64_t target = + (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; + BranchPrediction prediction = {direction, target}; + + // Amend prediction based on branch type + if (type == BranchType::Unconditional) { + prediction.isTaken = true; + } else if (type == BranchType::Return) { + prediction.isTaken = true; + // Return branches can use the RAS if an entry is available + if (ras_.size() > 0) { + prediction.target = ras_.back(); + // Record top of RAS used for target prediction + rasHistory_[address] = ras_.back(); + ras_.pop_back(); + } + } else if (type == BranchType::SubroutineCall) { + prediction.isTaken = true; + // Subroutine call branches must push their associated return address to RAS + if (ras_.size() >= rasSize_) { + ras_.pop_front(); + } + ras_.push_back(address + 4); + // Record that this address is a branch-and-link instruction + rasHistory_[address] = 0; + } else if (type == BranchType::Conditional) { + if (!prediction.isTaken) prediction.target = address + 4; + } + + // Store the hashed index for correct hashing in update() + ftq_.emplace_back(prediction.isTaken, hashedIndex); + + // Speculatively update the global history + globalHistory_ = + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; + + return prediction; +} } // namespace simeng diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 3c5337875a..343a4ca053 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -35,70 +35,6 @@ PerceptronPredictor::~PerceptronPredictor() { ftq_.clear(); } -BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, - int64_t knownOffset) { - // Get the hashed index for the prediction table. XOR the global history with - // the non-zero bits of the address, and then keep only the btbBits_ bits of - // the output to keep it in bounds of the prediction table. - // The address is shifted to remove the two least-significant bits as these - // are always 0 in an ISA with 4-byte aligned instructions. - uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - - // Retrieve the perceptron from the BTB - std::vector perceptron = btb_[hashedIndex].first; - - // Get dot product of perceptron and history - int64_t Pout = getDotProduct(perceptron, globalHistory_); - - // Determine direction prediction based on its sign - bool direction = (Pout >= 0); - - // If there is a known offset then calculate target accordingly, otherwise - // retrieve the target prediction from the btb. - uint64_t target = - (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; - - BranchPrediction prediction = {direction, target}; - - // Amend prediction based on branch type - if (type == BranchType::Unconditional) { - prediction.isTaken = true; - } else if (type == BranchType::Return) { - prediction.isTaken = true; - // Return branches can use the RAS if an entry is available - if (ras_.size() > 0) { - prediction.target = ras_.back(); - // Record top of RAS used for target prediction - rasHistory_[address] = ras_.back(); - ras_.pop_back(); - } - } else if (type == BranchType::SubroutineCall) { - prediction.isTaken = true; - // Subroutine call branches must push their associated return address to RAS - if (ras_.size() >= rasSize_) { - ras_.pop_front(); - } - ras_.push_back(address + 4); - // Record that this address is a branch-and-link instruction - rasHistory_[address] = 0; - } else if (type == BranchType::Conditional) { - if (!prediction.isTaken) prediction.target = address + 4; - } - - // Store the Pout and global history for correct update() -- - // needs to be global history and not the hashed index as hashing loses - // information and the global history is required for updating perceptrons. - ftq_.emplace_back(Pout, globalHistory_); - - // Speculatively update the global history based on the direction - // prediction being made - globalHistory_ = - ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; - - return prediction; -} - void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type, uint64_t instructionId) { @@ -186,6 +122,71 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } +BranchPrediction PerceptronPredictor::makePrediction(uint64_t address, + BranchType type, + int64_t knownOffset) { + // Get the hashed index for the prediction table. XOR the global history with + // the non-zero bits of the address, and then keep only the btbBits_ bits of + // the output to keep it in bounds of the prediction table. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in an ISA with 4-byte aligned instructions. + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + + // Retrieve the perceptron from the BTB + std::vector perceptron = btb_[hashedIndex].first; + + // Get dot product of perceptron and history + int64_t Pout = getDotProduct(perceptron, globalHistory_); + + // Determine direction prediction based on its sign + bool direction = (Pout >= 0); + + // If there is a known offset then calculate target accordingly, otherwise + // retrieve the target prediction from the btb. + uint64_t target = + (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; + + BranchPrediction prediction = {direction, target}; + + // Amend prediction based on branch type + if (type == BranchType::Unconditional) { + prediction.isTaken = true; + } else if (type == BranchType::Return) { + prediction.isTaken = true; + // Return branches can use the RAS if an entry is available + if (ras_.size() > 0) { + prediction.target = ras_.back(); + // Record top of RAS used for target prediction + rasHistory_[address] = ras_.back(); + ras_.pop_back(); + } + } else if (type == BranchType::SubroutineCall) { + prediction.isTaken = true; + // Subroutine call branches must push their associated return address to RAS + if (ras_.size() >= rasSize_) { + ras_.pop_front(); + } + ras_.push_back(address + 4); + // Record that this address is a branch-and-link instruction + rasHistory_[address] = 0; + } else if (type == BranchType::Conditional) { + if (!prediction.isTaken) prediction.target = address + 4; + } + + // Store the Pout and global history for correct update() -- + // needs to be global history and not the hashed index as hashing loses + // information and the global history is required for updating perceptrons. + ftq_.emplace_back(Pout, globalHistory_); + + // Speculatively update the global history based on the direction + // prediction being made + globalHistory_ = + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; + + return prediction; +} + int64_t PerceptronPredictor::getDotProduct( const std::vector& perceptron, uint64_t history) { int64_t Pout = perceptron[globalHistoryLength_]; diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index 2727e6db51..ca1486a795 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -14,6 +14,11 @@ class MockBranchPredictor : public BranchPredictor { void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type, uint64_t instructionId)); MOCK_METHOD1(flush, void(uint64_t address)); + + private: + MOCK_METHOD3(makePrediction, + BranchPrediction(uint64_t address, BranchType type, + int64_t knownTarget)); }; } // namespace simeng From b50b84d4bba0f3589170ccc2a4426ca3812c995b Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:17:02 +0100 Subject: [PATCH 184/191] Getting rid of default argument --- .../AlwaysNotTakenPredictor.hh | 9 +- .../branchpredictors/BranchPrediction.hh | 10 +- .../branchpredictors/BranchPredictor.hh | 35 ++--- .../branchpredictors/GenericPredictor.hh | 12 +- .../branchpredictors/PerceptronPredictor.hh | 12 +- .../AlwaysNotTakenPredictor.cc | 10 +- src/lib/branchpredictors/GenericPredictor.cc | 101 +++++++------- .../branchpredictors/PerceptronPredictor.cc | 129 +++++++++--------- src/lib/models/outoforder/Core.cc | 12 +- test/unit/MockBranchPredictor.hh | 5 - 10 files changed, 155 insertions(+), 180 deletions(-) diff --git a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh index f2722815fe..382a495420 100644 --- a/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh +++ b/src/include/simeng/branchpredictors/AlwaysNotTakenPredictor.hh @@ -8,6 +8,11 @@ namespace simeng { * taken. */ class AlwaysNotTakenPredictor : public BranchPredictor { public: + /** Generate a branch prediction for the specified instruction address; will + * always predict not taken. */ + BranchPrediction predict(uint64_t address, BranchType type, + int64_t knownOffset) override; + /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on * branches in program order. To check this, instructionId is also passed @@ -20,10 +25,6 @@ class AlwaysNotTakenPredictor : public BranchPredictor { void flush(uint64_t address) override; private: - /** Generate a branch prediction for the specified instruction address; will - * always predict not taken. */ - BranchPrediction makePrediction(uint64_t address, BranchType type, - int64_t knownOffset) override; }; } // namespace simeng diff --git a/src/include/simeng/branchpredictors/BranchPrediction.hh b/src/include/simeng/branchpredictors/BranchPrediction.hh index 243dffcaa5..aac7de52ea 100644 --- a/src/include/simeng/branchpredictors/BranchPrediction.hh +++ b/src/include/simeng/branchpredictors/BranchPrediction.hh @@ -25,18 +25,12 @@ struct BranchPrediction { /** Check for equality of two branch predictions . */ bool operator==(const BranchPrediction& other) { - if ((isTaken == other.isTaken) && (target == other.target)) - return true; - else - return false; + return ((isTaken == other.isTaken) && (target == other.target)); } /** Check for inequality of two branch predictions . */ bool operator!=(const BranchPrediction& other) { - if ((isTaken != other.isTaken) || (target != other.target)) - return true; - else - return false; + return ((isTaken != other.isTaken) || (target != other.target)); } }; diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index b7a9a6ff34..1cd5c60456 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -14,16 +14,11 @@ class BranchPredictor { public: virtual ~BranchPredictor(){}; - /** - * Wrapper function to provide default knownOffset to makePrediction, if - * needed. This is needed to avoid having to provide default values for - * knownOffset in each child class, and the risks associated with - * this interplay between default arguments and inheritance. - */ + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset. Returns a branch direction and + * branch target address. */ virtual BranchPrediction predict(uint64_t address, BranchType type, - int64_t knownOffset = 0) { - return makePrediction(address, type, knownOffset); - } + int64_t knownOffset) = 0; /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on @@ -46,14 +41,14 @@ class BranchPredictor { * branch instruction, flushes them. */ void flushBranchesInBufferFromSelf( - pipeline::PipelineBuffer> buffer) { - for (size_t slot = 0; slot < buffer.getWidth(); slot++) { - auto& uop = buffer.getTailSlots()[slot]; + pipeline::PipelineBuffer>* buffer) { + for (size_t slot = 0; slot < buffer->getWidth(); slot++) { + auto& uop = buffer->getTailSlots()[slot]; if (uop != nullptr && uop->isBranch()) { flush(uop->getInstructionAddress()); } - uop = buffer.getHeadSlots()[slot]; + uop = buffer->getHeadSlots()[slot]; if (uop != nullptr && uop->isBranch()) { flush(uop->getInstructionAddress()); } @@ -67,16 +62,16 @@ class BranchPredictor { * branch instruction, flushes them. */ void flushBranchesInBufferFromSelf( - pipeline::PipelineBuffer>> + pipeline::PipelineBuffer>>* buffer) { - for (size_t slot = 0; slot < buffer.getWidth(); slot++) { - auto& macroOp = buffer.getTailSlots()[slot]; + for (size_t slot = 0; slot < buffer->getWidth(); slot++) { + auto& macroOp = buffer->getTailSlots()[slot]; for (size_t uop = 0; uop < macroOp.size(); uop++) { if (macroOp[uop]->isBranch()) { flush(macroOp[uop]->getInstructionAddress()); } } - macroOp = buffer.getHeadSlots()[slot]; + macroOp = buffer->getHeadSlots()[slot]; for (size_t uop = 0; uop < macroOp.size(); uop++) { if (macroOp[uop]->isBranch()) { flush(macroOp[uop]->getInstructionAddress()); @@ -97,12 +92,6 @@ class BranchPredictor { * ensure that update is called in program order. */ uint64_t lastUpdatedInstructionId_ = 0; #endif - private: - /** Generate a branch prediction for the supplied instruction address, a - * branch type, and a known branch offset. Returns a branch direction and - * branch target address. */ - virtual BranchPrediction makePrediction(uint64_t address, BranchType type, - int64_t knownOffset) = 0; }; } // namespace simeng \ No newline at end of file diff --git a/src/include/simeng/branchpredictors/GenericPredictor.hh b/src/include/simeng/branchpredictors/GenericPredictor.hh index e4353aafda..ae1aff6d05 100644 --- a/src/include/simeng/branchpredictors/GenericPredictor.hh +++ b/src/include/simeng/branchpredictors/GenericPredictor.hh @@ -27,6 +27,12 @@ class GenericPredictor : public BranchPredictor { GenericPredictor(ryml::ConstNodeRef config = config::SimInfo::getConfig()); ~GenericPredictor(); + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset. Returns a branch direction and + * branch target address. */ + BranchPrediction predict(uint64_t address, BranchType type, + int64_t knownOffset) override; + /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on * branches in program order. To check this, instructionId is also passed @@ -42,12 +48,6 @@ class GenericPredictor : public BranchPredictor { void flush(uint64_t address) override; private: - /** Generate a branch prediction for the supplied instruction address, a - * branch type, and a known branch offset. Returns a branch direction and - * branch target address. */ - BranchPrediction makePrediction(uint64_t address, BranchType type, - int64_t knownOffset) override; - /** The bitlength of the BTB index; BTB will have 2^bits entries. */ uint8_t btbBits_; diff --git a/src/include/simeng/branchpredictors/PerceptronPredictor.hh b/src/include/simeng/branchpredictors/PerceptronPredictor.hh index 90efe6dc00..d9e05bca52 100644 --- a/src/include/simeng/branchpredictors/PerceptronPredictor.hh +++ b/src/include/simeng/branchpredictors/PerceptronPredictor.hh @@ -30,6 +30,12 @@ class PerceptronPredictor : public BranchPredictor { PerceptronPredictor(ryml::ConstNodeRef config = config::SimInfo::getConfig()); ~PerceptronPredictor(); + /** Generate a branch prediction for the supplied instruction address, a + * branch type, and a known branch offset. Returns a branch direction and + * branch target address. */ + BranchPrediction predict(uint64_t address, BranchType type, + int64_t knownOffset) override; + /** Updates appropriate predictor model objects based on the address, type and * outcome of the branch instruction. Update must be called on * branches in program order. To check this, instructionId is also passed @@ -45,12 +51,6 @@ class PerceptronPredictor : public BranchPredictor { void flush(uint64_t address) override; private: - /** Generate a branch prediction for the supplied instruction address, a - * branch type, and a known branch offset. Returns a branch direction and - * branch target address. */ - BranchPrediction makePrediction(uint64_t address, BranchType type, - int64_t knownOffset) override; - /** Returns the dot product of a perceptron and a history vector. Used to * determine a direction prediction */ int64_t getDotProduct(const std::vector& perceptron, diff --git a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index 15dcb749eb..c22639476b 100644 --- a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -1,16 +1,14 @@ #include "simeng/branchpredictors/AlwaysNotTakenPredictor.hh" namespace simeng { +BranchPrediction AlwaysNotTakenPredictor::predict( + [[maybe_unused]] uint64_t address, BranchType type, int64_t knownOffset) { + return { false, 0 }; +} void AlwaysNotTakenPredictor::update(uint64_t address, bool taken, uint64_t targetAddress, BranchType type, uint64_t instructionId) {} void AlwaysNotTakenPredictor::flush(uint64_t address) {} - -BranchPrediction AlwaysNotTakenPredictor::makePrediction( - [[maybe_unused]] uint64_t address, BranchType type, int64_t knownOffset) { - return {false, 0}; -} - } // namespace simeng diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index ba2d377f45..a79289a62c 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -37,6 +37,56 @@ GenericPredictor::~GenericPredictor() { ftq_.clear(); } +BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, + int64_t knownOffset) { + // Get index via an XOR hash between the global history and the instruction + // address. This hash is then ANDed to keep it within bounds of the btb. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in an ISA with 4-byte aligned instructions. + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + + // Get prediction from BTB + bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); + uint64_t target = + (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; + BranchPrediction prediction = {direction, target}; + + // Amend prediction based on branch type + if (type == BranchType::Unconditional) { + prediction.isTaken = true; + } else if (type == BranchType::Return) { + prediction.isTaken = true; + // Return branches can use the RAS if an entry is available + if (ras_.size() > 0) { + prediction.target = ras_.back(); + // Record top of RAS used for target prediction + rasHistory_[address] = ras_.back(); + ras_.pop_back(); + } + } else if (type == BranchType::SubroutineCall) { + prediction.isTaken = true; + // Subroutine call branches must push their associated return address to RAS + if (ras_.size() >= rasSize_) { + ras_.pop_front(); + } + ras_.push_back(address + 4); + // Record that this address is a branch-and-link instruction + rasHistory_[address] = 0; + } else if (type == BranchType::Conditional) { + if (!prediction.isTaken) prediction.target = address + 4; + } + + // Store the hashed index for correct hashing in update() + ftq_.emplace_back(prediction.isTaken, hashedIndex); + + // Speculatively update the global history + globalHistory_ = + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; + + return prediction; +} + void GenericPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type, uint64_t instructionId) { @@ -103,55 +153,4 @@ void GenericPredictor::flush(uint64_t address) { // Roll back global history globalHistory_ >>= 1; } - -BranchPrediction GenericPredictor::makePrediction(uint64_t address, - BranchType type, - int64_t knownOffset) { - // Get index via an XOR hash between the global history and the instruction - // address. This hash is then ANDed to keep it within bounds of the btb. - // The address is shifted to remove the two least-significant bits as these - // are always 0 in an ISA with 4-byte aligned instructions. - uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - - // Get prediction from BTB - bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); - uint64_t target = - (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; - BranchPrediction prediction = {direction, target}; - - // Amend prediction based on branch type - if (type == BranchType::Unconditional) { - prediction.isTaken = true; - } else if (type == BranchType::Return) { - prediction.isTaken = true; - // Return branches can use the RAS if an entry is available - if (ras_.size() > 0) { - prediction.target = ras_.back(); - // Record top of RAS used for target prediction - rasHistory_[address] = ras_.back(); - ras_.pop_back(); - } - } else if (type == BranchType::SubroutineCall) { - prediction.isTaken = true; - // Subroutine call branches must push their associated return address to RAS - if (ras_.size() >= rasSize_) { - ras_.pop_front(); - } - ras_.push_back(address + 4); - // Record that this address is a branch-and-link instruction - rasHistory_[address] = 0; - } else if (type == BranchType::Conditional) { - if (!prediction.isTaken) prediction.target = address + 4; - } - - // Store the hashed index for correct hashing in update() - ftq_.emplace_back(prediction.isTaken, hashedIndex); - - // Speculatively update the global history - globalHistory_ = - ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; - - return prediction; -} } // namespace simeng diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 343a4ca053..3c5337875a 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -35,6 +35,70 @@ PerceptronPredictor::~PerceptronPredictor() { ftq_.clear(); } +BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, + int64_t knownOffset) { + // Get the hashed index for the prediction table. XOR the global history with + // the non-zero bits of the address, and then keep only the btbBits_ bits of + // the output to keep it in bounds of the prediction table. + // The address is shifted to remove the two least-significant bits as these + // are always 0 in an ISA with 4-byte aligned instructions. + uint64_t hashedIndex = + ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + + // Retrieve the perceptron from the BTB + std::vector perceptron = btb_[hashedIndex].first; + + // Get dot product of perceptron and history + int64_t Pout = getDotProduct(perceptron, globalHistory_); + + // Determine direction prediction based on its sign + bool direction = (Pout >= 0); + + // If there is a known offset then calculate target accordingly, otherwise + // retrieve the target prediction from the btb. + uint64_t target = + (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; + + BranchPrediction prediction = {direction, target}; + + // Amend prediction based on branch type + if (type == BranchType::Unconditional) { + prediction.isTaken = true; + } else if (type == BranchType::Return) { + prediction.isTaken = true; + // Return branches can use the RAS if an entry is available + if (ras_.size() > 0) { + prediction.target = ras_.back(); + // Record top of RAS used for target prediction + rasHistory_[address] = ras_.back(); + ras_.pop_back(); + } + } else if (type == BranchType::SubroutineCall) { + prediction.isTaken = true; + // Subroutine call branches must push their associated return address to RAS + if (ras_.size() >= rasSize_) { + ras_.pop_front(); + } + ras_.push_back(address + 4); + // Record that this address is a branch-and-link instruction + rasHistory_[address] = 0; + } else if (type == BranchType::Conditional) { + if (!prediction.isTaken) prediction.target = address + 4; + } + + // Store the Pout and global history for correct update() -- + // needs to be global history and not the hashed index as hashing loses + // information and the global history is required for updating perceptrons. + ftq_.emplace_back(Pout, globalHistory_); + + // Speculatively update the global history based on the direction + // prediction being made + globalHistory_ = + ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; + + return prediction; +} + void PerceptronPredictor::update(uint64_t address, bool isTaken, uint64_t targetAddress, BranchType type, uint64_t instructionId) { @@ -122,71 +186,6 @@ void PerceptronPredictor::flush(uint64_t address) { globalHistory_ >>= 1; } -BranchPrediction PerceptronPredictor::makePrediction(uint64_t address, - BranchType type, - int64_t knownOffset) { - // Get the hashed index for the prediction table. XOR the global history with - // the non-zero bits of the address, and then keep only the btbBits_ bits of - // the output to keep it in bounds of the prediction table. - // The address is shifted to remove the two least-significant bits as these - // are always 0 in an ISA with 4-byte aligned instructions. - uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); - - // Retrieve the perceptron from the BTB - std::vector perceptron = btb_[hashedIndex].first; - - // Get dot product of perceptron and history - int64_t Pout = getDotProduct(perceptron, globalHistory_); - - // Determine direction prediction based on its sign - bool direction = (Pout >= 0); - - // If there is a known offset then calculate target accordingly, otherwise - // retrieve the target prediction from the btb. - uint64_t target = - (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; - - BranchPrediction prediction = {direction, target}; - - // Amend prediction based on branch type - if (type == BranchType::Unconditional) { - prediction.isTaken = true; - } else if (type == BranchType::Return) { - prediction.isTaken = true; - // Return branches can use the RAS if an entry is available - if (ras_.size() > 0) { - prediction.target = ras_.back(); - // Record top of RAS used for target prediction - rasHistory_[address] = ras_.back(); - ras_.pop_back(); - } - } else if (type == BranchType::SubroutineCall) { - prediction.isTaken = true; - // Subroutine call branches must push their associated return address to RAS - if (ras_.size() >= rasSize_) { - ras_.pop_front(); - } - ras_.push_back(address + 4); - // Record that this address is a branch-and-link instruction - rasHistory_[address] = 0; - } else if (type == BranchType::Conditional) { - if (!prediction.isTaken) prediction.target = address + 4; - } - - // Store the Pout and global history for correct update() -- - // needs to be global history and not the hashed index as hashing loses - // information and the global history is required for updating perceptrons. - ftq_.emplace_back(Pout, globalHistory_); - - // Speculatively update the global history based on the direction - // prediction being made - globalHistory_ = - ((globalHistory_ << 1) | prediction.isTaken) & globalHistoryMask_; - - return prediction; -} - int64_t PerceptronPredictor::getDotProduct( const std::vector& perceptron, uint64_t history) { int64_t Pout = perceptron[globalHistoryLength_]; diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 1c518d2e63..7ee15e7d1a 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -228,7 +228,7 @@ std::map Core::getStats() const { uint64_t totalBranchesRetired = reorderBuffer_.getRetiredBranchesCount(); uint64_t totalBranchMispredicts = reorderBuffer_.getBranchMispredictedCount(); - auto branchMissRate = 100.0f * static_cast(totalBranchMispredicts) / + auto branchMissRate = 100.0 * static_cast(totalBranchMispredicts) / static_cast(totalBranchesRetired); std::ostringstream branchMissRateStr; branchMissRateStr << std::setprecision(3) << branchMissRate << "%"; @@ -263,11 +263,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check for branch instructions in buffer, and flush them from the BP. // Then empty the buffers - branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(&fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - branchPredictor_.flushBranchesInBufferFromSelf(decodeToRenameBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(&decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -351,11 +351,11 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(&fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - branchPredictor_.flushBranchesInBufferFromSelf(decodeToRenameBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(&decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -383,7 +383,7 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(&fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); diff --git a/test/unit/MockBranchPredictor.hh b/test/unit/MockBranchPredictor.hh index ca1486a795..2727e6db51 100644 --- a/test/unit/MockBranchPredictor.hh +++ b/test/unit/MockBranchPredictor.hh @@ -14,11 +14,6 @@ class MockBranchPredictor : public BranchPredictor { void(uint64_t address, bool taken, uint64_t targetAddress, BranchType type, uint64_t instructionId)); MOCK_METHOD1(flush, void(uint64_t address)); - - private: - MOCK_METHOD3(makePrediction, - BranchPrediction(uint64_t address, BranchType type, - int64_t knownTarget)); }; } // namespace simeng From 95d384dc2d153512a30dd25a55491bd675fb21a8 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:17:23 +0100 Subject: [PATCH 185/191] Getting rid of default argument --- src/lib/branchpredictors/AlwaysNotTakenPredictor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc index c22639476b..f9ccb416bc 100644 --- a/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc +++ b/src/lib/branchpredictors/AlwaysNotTakenPredictor.cc @@ -3,7 +3,7 @@ namespace simeng { BranchPrediction AlwaysNotTakenPredictor::predict( [[maybe_unused]] uint64_t address, BranchType type, int64_t knownOffset) { - return { false, 0 }; + return {false, 0}; } void AlwaysNotTakenPredictor::update(uint64_t address, bool taken, From 3a2b1ab6f5b538cbfba6b5ded6e963c9e4806629 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:45:26 +0100 Subject: [PATCH 186/191] Going to ull when shifting --- src/lib/branchpredictors/GenericPredictor.cc | 8 ++++---- .../branchpredictors/PerceptronPredictor.cc | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index a79289a62c..2605b1e302 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -44,10 +44,10 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // The address is shifted to remove the two least-significant bits as these // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + ((address >> 2) ^ globalHistory_) & ((1ull << btbBits_) - 1); // Get prediction from BTB - bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); + bool direction = btb_[hashedIndex].first >= (1ull << (satCntBits_ - 1)); uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; BranchPrediction prediction = {direction, target}; @@ -104,7 +104,7 @@ void GenericPredictor::update(uint64_t address, bool isTaken, // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; // Only alter value if it would transition to a valid state - if (!((satCntVal == (1 << satCntBits_) - 1) && isTaken) && + if (!((satCntVal == ((uint8_t)1 << satCntBits_) - 1) && isTaken) && !(satCntVal == 0 && !isTaken)) { satCntVal += isTaken ? 1 : -1; } @@ -119,7 +119,7 @@ void GenericPredictor::update(uint64_t address, bool isTaken, if (prevPrediction != isTaken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << (ftq_.size())); + globalHistory_ ^= (1ull << (ftq_.size())); } } diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 3c5337875a..2e517939eb 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -8,7 +8,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) config["Branch-Predictor"]["Global-History-Length"].as()), rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { // Build BTB based on config options - uint32_t btbSize = (1 << btbBits_); + uint32_t btbSize = (1ul << btbBits_); btb_.resize(btbSize); // Initialise perceptron values with 0 for the global history weights, and 1 @@ -26,7 +26,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // bits are stored in the global history. This is two times the // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. - globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + globalHistoryMask_ = (1ull << (globalHistoryLength_ * 2)) - 1; } PerceptronPredictor::~PerceptronPredictor() { @@ -43,7 +43,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // The address is shifted to remove the two least-significant bits as these // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + ((address >> 2) ^ globalHistory_) & ((1ull << btbBits_) - 1); // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -116,7 +116,7 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Work out hashed index uint64_t hashedIndex = - ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); + ((address >> 2) ^ prevGlobalHistory) & ((1ull << btbBits_) - 1); std::vector perceptron = btb_[hashedIndex].first; @@ -130,10 +130,10 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, int8_t t = (isTaken) ? 1 : -1; for (uint64_t i = 0; i < globalHistoryLength_; i++) { - int8_t xi = - ((prevGlobalHistory & (1 << ((globalHistoryLength_ - 1) - i))) == 0) - ? -1 - : 1; + int8_t xi = ((prevGlobalHistory & + (1ull << ((globalHistoryLength_ - 1) - i))) == 0) + ? -1 + : 1; int8_t product_xi_t = xi * t; // Make sure no overflow (+-127) if (!(perceptron[i] == 127 && product_xi_t == 1) && @@ -152,7 +152,7 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (directionPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); + if (directionPrediction != isTaken) globalHistory_ ^= (1ull << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -192,7 +192,7 @@ int64_t PerceptronPredictor::getDotProduct( for (uint64_t i = 0; i < globalHistoryLength_; i++) { // Get branch direction for ith entry in the history bool historyTaken = - ((history & (1 << ((globalHistoryLength_ - 1) - i))) != 0); + ((history & (1ull << ((globalHistoryLength_ - 1) - i))) != 0); Pout += historyTaken ? perceptron[i] : (0 - perceptron[i]); } return Pout; From abfc2f1880dcecd1b93350847f42de2a5faa7176 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:25:40 +0100 Subject: [PATCH 187/191] Going to ull when shifting --- src/lib/branchpredictors/GenericPredictor.cc | 8 ++++---- .../branchpredictors/PerceptronPredictor.cc | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index a79289a62c..2605b1e302 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -44,10 +44,10 @@ BranchPrediction GenericPredictor::predict(uint64_t address, BranchType type, // The address is shifted to remove the two least-significant bits as these // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + ((address >> 2) ^ globalHistory_) & ((1ull << btbBits_) - 1); // Get prediction from BTB - bool direction = btb_[hashedIndex].first >= (1 << (satCntBits_ - 1)); + bool direction = btb_[hashedIndex].first >= (1ull << (satCntBits_ - 1)); uint64_t target = (knownOffset != 0) ? address + knownOffset : btb_[hashedIndex].second; BranchPrediction prediction = {direction, target}; @@ -104,7 +104,7 @@ void GenericPredictor::update(uint64_t address, bool isTaken, // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; // Only alter value if it would transition to a valid state - if (!((satCntVal == (1 << satCntBits_) - 1) && isTaken) && + if (!((satCntVal == ((uint8_t)1 << satCntBits_) - 1) && isTaken) && !(satCntVal == 0 && !isTaken)) { satCntVal += isTaken ? 1 : -1; } @@ -119,7 +119,7 @@ void GenericPredictor::update(uint64_t address, bool isTaken, if (prevPrediction != isTaken) { // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - globalHistory_ ^= (1 << (ftq_.size())); + globalHistory_ ^= (1ull << (ftq_.size())); } } diff --git a/src/lib/branchpredictors/PerceptronPredictor.cc b/src/lib/branchpredictors/PerceptronPredictor.cc index 3c5337875a..2e517939eb 100644 --- a/src/lib/branchpredictors/PerceptronPredictor.cc +++ b/src/lib/branchpredictors/PerceptronPredictor.cc @@ -8,7 +8,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) config["Branch-Predictor"]["Global-History-Length"].as()), rasSize_(config["Branch-Predictor"]["RAS-entries"].as()) { // Build BTB based on config options - uint32_t btbSize = (1 << btbBits_); + uint32_t btbSize = (1ul << btbBits_); btb_.resize(btbSize); // Initialise perceptron values with 0 for the global history weights, and 1 @@ -26,7 +26,7 @@ PerceptronPredictor::PerceptronPredictor(ryml::ConstNodeRef config) // bits are stored in the global history. This is two times the // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. - globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + globalHistoryMask_ = (1ull << (globalHistoryLength_ * 2)) - 1; } PerceptronPredictor::~PerceptronPredictor() { @@ -43,7 +43,7 @@ BranchPrediction PerceptronPredictor::predict(uint64_t address, BranchType type, // The address is shifted to remove the two least-significant bits as these // are always 0 in an ISA with 4-byte aligned instructions. uint64_t hashedIndex = - ((address >> 2) ^ globalHistory_) & ((1 << btbBits_) - 1); + ((address >> 2) ^ globalHistory_) & ((1ull << btbBits_) - 1); // Retrieve the perceptron from the BTB std::vector perceptron = btb_[hashedIndex].first; @@ -116,7 +116,7 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Work out hashed index uint64_t hashedIndex = - ((address >> 2) ^ prevGlobalHistory) & ((1 << btbBits_) - 1); + ((address >> 2) ^ prevGlobalHistory) & ((1ull << btbBits_) - 1); std::vector perceptron = btb_[hashedIndex].first; @@ -130,10 +130,10 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, int8_t t = (isTaken) ? 1 : -1; for (uint64_t i = 0; i < globalHistoryLength_; i++) { - int8_t xi = - ((prevGlobalHistory & (1 << ((globalHistoryLength_ - 1) - i))) == 0) - ? -1 - : 1; + int8_t xi = ((prevGlobalHistory & + (1ull << ((globalHistoryLength_ - 1) - i))) == 0) + ? -1 + : 1; int8_t product_xi_t = xi * t; // Make sure no overflow (+-127) if (!(perceptron[i] == 127 && product_xi_t == 1) && @@ -152,7 +152,7 @@ void PerceptronPredictor::update(uint64_t address, bool isTaken, // Update global history if prediction was incorrect // Bit-flip the global history bit corresponding to this prediction // We know how many predictions there have since been by the size of the FTQ - if (directionPrediction != isTaken) globalHistory_ ^= (1 << (ftq_.size())); + if (directionPrediction != isTaken) globalHistory_ ^= (1ull << (ftq_.size())); } void PerceptronPredictor::flush(uint64_t address) { @@ -192,7 +192,7 @@ int64_t PerceptronPredictor::getDotProduct( for (uint64_t i = 0; i < globalHistoryLength_; i++) { // Get branch direction for ith entry in the history bool historyTaken = - ((history & (1 << ((globalHistoryLength_ - 1) - i))) != 0); + ((history & (1ull << ((globalHistoryLength_ - 1) - i))) != 0); Pout += historyTaken ? perceptron[i] : (0 - perceptron[i]); } return Pout; From d7e0dbb9e8d5abceb0f92cf01a999f99b7395d8e Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:52:06 +0100 Subject: [PATCH 188/191] Adding comments --- .jenkins/build_test_run.sh | 4 +++- src/lib/branchpredictors/GenericPredictor.cc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.jenkins/build_test_run.sh b/.jenkins/build_test_run.sh index dcc3e78a6e..b76867a2fe 100644 --- a/.jenkins/build_test_run.sh +++ b/.jenkins/build_test_run.sh @@ -55,6 +55,8 @@ test () { } # Run default program with and without specified configuration +# Space needed before 'retired' and 'cycles' to differentiate from other +# subfeilds. E.g., 'branches.retired' run () { cd "$SIMENG_INSTALL" || exit @@ -71,7 +73,7 @@ run () { cat run echo "" compare_outputs "$(grep " retired:" run | rev | cut -d ' ' -f1 | rev)" "6724" "retired instructions" - compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" "7496" "simulated cycles" + compare_outputs "$(grep " cycles:" run | rev | cut -d ' ' -f1 | rev)" "7867" "simulated cycles" echo "" } diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index 2605b1e302..c242866d29 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -104,7 +104,7 @@ void GenericPredictor::update(uint64_t address, bool isTaken, // Calculate 2-bit saturating counter value uint8_t satCntVal = btb_[hashedIndex].first; // Only alter value if it would transition to a valid state - if (!((satCntVal == ((uint8_t)1 << satCntBits_) - 1) && isTaken) && + if (!((satCntVal == (1 << satCntBits_) - 1) && isTaken) && !(satCntVal == 0 && !isTaken)) { satCntVal += isTaken ? 1 : -1; } From e58902bd95c97258bcdfde152b186dbc3f11a414 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:06:07 +0100 Subject: [PATCH 189/191] Updating comments --- src/include/simeng/branchpredictors/BranchPredictor.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 1cd5c60456..3aaacdcbfd 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -36,7 +36,7 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts PipelineBuffers of microOps. + * PipelineBuffer. Accepts a reference to a PipelineBuffer of microOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ @@ -57,7 +57,7 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts PipelineBuffers macroOps. + * PipelineBuffer. Accepts a reference to a PipelineBuffer macroOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ From 98459d361e07dc57951cc18998443e26e860ee74 Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Aug 2024 14:52:08 +0100 Subject: [PATCH 190/191] Addressing Jack's comments --- src/include/simeng/branchpredictors/BranchPredictor.hh | 4 ++-- src/lib/branchpredictors/GenericPredictor.cc | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 3aaacdcbfd..8e1651d1e4 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -36,7 +36,7 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts a reference to a PipelineBuffer of microOps. + * PipelineBuffer. Accepts a pointer to a PipelineBuffer of microOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ @@ -57,7 +57,7 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts a reference to a PipelineBuffer macroOps. + * PipelineBuffer. Accepts a pointer to a PipelineBuffer macroOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ diff --git a/src/lib/branchpredictors/GenericPredictor.cc b/src/lib/branchpredictors/GenericPredictor.cc index c242866d29..50e93e5f76 100644 --- a/src/lib/branchpredictors/GenericPredictor.cc +++ b/src/lib/branchpredictors/GenericPredictor.cc @@ -21,13 +21,14 @@ GenericPredictor::GenericPredictor(ryml::ConstNodeRef config) : (weaklyTaken - 1); // Create branch prediction structures btb_ = - std::vector>(1 << btbBits_, {satCntVal, 0}); + std::vector>(1ull << btbBits_, + {satCntVal, 0}); // Generate a bitmask that is used to ensure only the relevant number of // bits are stored in the global history. This is two times the // globalHistoryLength_ to allow rolling back of the speculatively updated // global history in the event of a misprediction. - globalHistoryMask_ = (1 << (globalHistoryLength_ * 2)) - 1; + globalHistoryMask_ = (1ull << (globalHistoryLength_ * 2)) - 1; } GenericPredictor::~GenericPredictor() { From aec467dc4ddf14343352de163f303671c4349dae Mon Sep 17 00:00:00 2001 From: Alex Cockrean <84676155+ABenC377@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:00:48 +0100 Subject: [PATCH 191/191] Replacing pointers with references --- .../branchpredictors/BranchPredictor.hh | 20 +++++++++---------- src/lib/models/outoforder/Core.cc | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/include/simeng/branchpredictors/BranchPredictor.hh b/src/include/simeng/branchpredictors/BranchPredictor.hh index 8e1651d1e4..7779fe0703 100644 --- a/src/include/simeng/branchpredictors/BranchPredictor.hh +++ b/src/include/simeng/branchpredictors/BranchPredictor.hh @@ -36,19 +36,19 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts a pointer to a PipelineBuffer of microOps. + * PipelineBuffer. Accepts a reference to a PipelineBuffer of microOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ void flushBranchesInBufferFromSelf( - pipeline::PipelineBuffer>* buffer) { - for (size_t slot = 0; slot < buffer->getWidth(); slot++) { - auto& uop = buffer->getTailSlots()[slot]; + pipeline::PipelineBuffer>& buffer) { + for (size_t slot = 0; slot < buffer.getWidth(); slot++) { + auto& uop = buffer.getTailSlots()[slot]; if (uop != nullptr && uop->isBranch()) { flush(uop->getInstructionAddress()); } - uop = buffer->getHeadSlots()[slot]; + uop = buffer.getHeadSlots()[slot]; if (uop != nullptr && uop->isBranch()) { flush(uop->getInstructionAddress()); } @@ -57,21 +57,21 @@ class BranchPredictor { /** * Overloaded function for flushing branch instructions from a - * PipelineBuffer. Accepts a pointer to a PipelineBuffer macroOps. + * PipelineBuffer. Accepts a reference to a PipelineBuffer macroOps. * Iterates over the entries of the PipelineBuffer and, if they are a * branch instruction, flushes them. */ void flushBranchesInBufferFromSelf( - pipeline::PipelineBuffer>>* + pipeline::PipelineBuffer>>& buffer) { - for (size_t slot = 0; slot < buffer->getWidth(); slot++) { - auto& macroOp = buffer->getTailSlots()[slot]; + for (size_t slot = 0; slot < buffer.getWidth(); slot++) { + auto& macroOp = buffer.getTailSlots()[slot]; for (size_t uop = 0; uop < macroOp.size(); uop++) { if (macroOp[uop]->isBranch()) { flush(macroOp[uop]->getInstructionAddress()); } } - macroOp = buffer->getHeadSlots()[slot]; + macroOp = buffer.getHeadSlots()[slot]; for (size_t uop = 0; uop < macroOp.size(); uop++) { if (macroOp[uop]->isBranch()) { flush(macroOp[uop]->getInstructionAddress()); diff --git a/src/lib/models/outoforder/Core.cc b/src/lib/models/outoforder/Core.cc index 7ee15e7d1a..af920e32aa 100644 --- a/src/lib/models/outoforder/Core.cc +++ b/src/lib/models/outoforder/Core.cc @@ -263,11 +263,11 @@ void Core::raiseException(const std::shared_ptr& instruction) { void Core::handleException() { // Check for branch instructions in buffer, and flush them from the BP. // Then empty the buffers - branchPredictor_.flushBranchesInBufferFromSelf(&fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - branchPredictor_.flushBranchesInBufferFromSelf(&decodeToRenameBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -351,11 +351,11 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - branchPredictor_.flushBranchesInBufferFromSelf(&fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false); - branchPredictor_.flushBranchesInBufferFromSelf(&decodeToRenameBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(decodeToRenameBuffer_); decodeToRenameBuffer_.fill(nullptr); decodeToRenameBuffer_.stall(false); @@ -383,7 +383,7 @@ void Core::flushIfNeeded() { // Then empty the buffers fetchUnit_.flushLoopBuffer(); fetchUnit_.updatePC(targetAddress); - branchPredictor_.flushBranchesInBufferFromSelf(&fetchToDecodeBuffer_); + branchPredictor_.flushBranchesInBufferFromSelf(fetchToDecodeBuffer_); fetchToDecodeBuffer_.fill({}); fetchToDecodeBuffer_.stall(false);