diff --git a/src/include/simeng/Instruction.hh b/src/include/simeng/Instruction.hh index b5a4e33e3b..c6c9c78bcb 100644 --- a/src/include/simeng/Instruction.hh +++ b/src/include/simeng/Instruction.hh @@ -73,12 +73,6 @@ class Instruction { /** Retrieve supplied memory data. */ virtual span getData() const = 0; - /** Early misprediction check; see if it's possible to determine whether the - * next instruction address was mispredicted without executing the - * instruction. Returns a {mispredicted, target} tuple representing whether - * the instruction was mispredicted, and the correct target address. */ - virtual std::tuple checkEarlyBranchMisprediction() const = 0; - /** Retrieve branch type. */ virtual BranchType getBranchType() const = 0; diff --git a/src/include/simeng/arch/aarch64/Instruction.hh b/src/include/simeng/arch/aarch64/Instruction.hh index b5f1f07cc5..d510c1f373 100644 --- a/src/include/simeng/arch/aarch64/Instruction.hh +++ b/src/include/simeng/arch/aarch64/Instruction.hh @@ -338,12 +338,6 @@ class Instruction : public simeng::Instruction { /** Retrieve supplied memory data. */ span getData() const override; - /** Early misprediction check; see if it's possible to determine whether the - * next instruction address was mispredicted without executing the - * instruction. Returns a {mispredicted, target} tuple representing whether - * the instruction was mispredicted, and the correct target address. */ - std::tuple checkEarlyBranchMisprediction() const override; - /** Retrieve branch type. */ BranchType getBranchType() const override; diff --git a/src/include/simeng/arch/riscv/Instruction.hh b/src/include/simeng/arch/riscv/Instruction.hh index 9e707449c6..62b6c0b8b5 100644 --- a/src/include/simeng/arch/riscv/Instruction.hh +++ b/src/include/simeng/arch/riscv/Instruction.hh @@ -132,12 +132,6 @@ class Instruction : public simeng::Instruction { /** Retrieve supplied memory data. */ span getData() const override; - /** Early misprediction check; see if it's possible to determine whether the - * next instruction address was mispredicted without executing the - * instruction. Returns a {mispredicted, target} tuple representing whether - * the instruction was mispredicted, and the correct target address. */ - std::tuple checkEarlyBranchMisprediction() const override; - /** Retrieve branch type. */ BranchType getBranchType() const override; diff --git a/src/lib/arch/aarch64/Instruction.cc b/src/lib/arch/aarch64/Instruction.cc index e3b697433e..755d0235b8 100644 --- a/src/lib/arch/aarch64/Instruction.cc +++ b/src/lib/arch/aarch64/Instruction.cc @@ -100,21 +100,6 @@ span Instruction::getData() const { return {memoryData_.data(), memoryData_.size()}; } -std::tuple Instruction::checkEarlyBranchMisprediction() const { - assert( - !executed_ && - "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 - // flush - return {prediction_.isTaken, instructionAddress_ + 4}; - } - - // Not enough information to determine this was a misprediction - return {false, 0}; -} - BranchType Instruction::getBranchType() const { return branchType_; } int64_t Instruction::getKnownOffset() const { return knownOffset_; } diff --git a/src/lib/arch/riscv/Instruction.cc b/src/lib/arch/riscv/Instruction.cc index c71b581a60..a0937aa9e7 100644 --- a/src/lib/arch/riscv/Instruction.cc +++ b/src/lib/arch/riscv/Instruction.cc @@ -95,21 +95,6 @@ span Instruction::getData() const { return {memoryData_.data(), memoryData_.size()}; } -std::tuple Instruction::checkEarlyBranchMisprediction() const { - assert( - !executed_ && - "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 - // flush - return {prediction_.isTaken, instructionAddress_ + 4}; - } - - // Not enough information to determine this was a misprediction - return {false, 0}; -} - BranchType Instruction::getBranchType() const { return branchType_; } int64_t Instruction::getKnownOffset() const { return knownOffset_; } diff --git a/src/lib/pipeline/DecodeUnit.cc b/src/lib/pipeline/DecodeUnit.cc index 31df59fa66..997d8fbab0 100644 --- a/src/lib/pipeline/DecodeUnit.cc +++ b/src/lib/pipeline/DecodeUnit.cc @@ -48,44 +48,8 @@ void DecodeUnit::tick() { if (!microOps_.size()) break; // Move uop to output buffer and remove from internal buffer - auto& uop = (output_.getTailSlots()[slot] = std::move(microOps_.front())); + output_.getTailSlots()[slot] = std::move(microOps_.front()); microOps_.pop_front(); - - // Check preliminary branch prediction results now that the instruction is - // decoded. Identifies: - // - Non-branch instructions mistakenly predicted as branches - // - Incorrect targets for immediate branches - auto [misprediction, correctAddress] = uop->checkEarlyBranchMisprediction(); - if (misprediction) { - earlyFlushes_++; - shouldFlush_ = true; - pc_ = correctAddress; - - if (!uop->isBranch()) { - // Non-branch incorrectly predicted as a branch; let the predictor know - predictor_.update(uop->getInstructionAddress(), false, pc_, - uop->getBranchType(), uop->getInstructionId()); - } - // Remove macro-operations in microOps_ buffer after macro-operation - // decoded in this cycle - auto uopIt = microOps_.begin(); - // Find first microOps_ entry not belonging to same address as flushing - // instruction - while (uopIt != microOps_.end()) { - if ((*uopIt)->getInstructionAddress() != uop->getInstructionAddress()) { - break; - } else { - uopIt++; - } - } - // Remove all entries after first macro-operation in buffer - while (uopIt != microOps_.end()) { - uopIt = microOps_.erase(uopIt); - } - - // Skip processing remaining uops, as they need to be flushed - break; - } } } diff --git a/test/unit/aarch64/InstructionTest.cc b/test/unit/aarch64/InstructionTest.cc index 1ecf14a1a6..7e3f399de0 100644 --- a/test/unit/aarch64/InstructionTest.cc +++ b/test/unit/aarch64/InstructionTest.cc @@ -461,38 +461,6 @@ TEST_F(AArch64InstructionTest, supplyData_dataAbort) { EXPECT_EQ(insn.getException(), InstructionException::DataAbort); } -// Test to check logic around early branch misprediction logic -TEST_F(AArch64InstructionTest, earlyBranchMisprediction) { - // Insn is `fdivr z1.s, p0/m, z1.s, z0.s` - Instruction insn = Instruction(arch, *fdivMetadata.get(), MicroOpInfo()); - insn.setInstructionAddress(64); - - // Check initial state of an instruction's branch related options - BranchPrediction pred = {false, 0}; - bool matchingPred = (insn.getBranchPrediction() == pred); - EXPECT_TRUE(matchingPred); - EXPECT_FALSE(insn.wasBranchTaken()); - EXPECT_EQ(insn.getBranchAddress(), 0); - EXPECT_EQ(insn.getBranchType(), BranchType::Unknown); - EXPECT_FALSE(insn.isBranch()); - std::tuple tup = {false, insn.getInstructionAddress() + 4}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - - // Set prediction and ensure expected state changes / outcomes are seen - pred = {true, 0x4848}; - insn.setBranchPrediction(pred); - matchingPred = (insn.getBranchPrediction() == pred); - EXPECT_TRUE(matchingPred); - EXPECT_FALSE(insn.wasBranchTaken()); - EXPECT_EQ(insn.getBranchAddress(), 0); - EXPECT_EQ(insn.getBranchType(), BranchType::Unknown); - // Check logic of `checkEarlyBranchMisprediction` which is different for - // non-branch instructions - EXPECT_FALSE(insn.isBranch()); - tup = {true, insn.getInstructionAddress() + 4}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); -} - // Test that a correct prediction (branch taken) is handled correctly TEST_F(AArch64InstructionTest, correctPred_taken) { // insn is `cbz x2, #0x28` @@ -507,8 +475,6 @@ TEST_F(AArch64InstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test a correct prediction where branch is taken is handled correctly pred = {true, 80 + 0x28}; @@ -536,8 +502,6 @@ TEST_F(AArch64InstructionTest, correctPred_notTaken) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test a correct prediction where a branch isn't taken is handled correctly pred = {false, 80 + 4}; @@ -565,8 +529,6 @@ TEST_F(AArch64InstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test an incorrect prediction is handled correctly - target is wrong pred = {true, 80 + 0x28}; @@ -594,8 +556,6 @@ TEST_F(AArch64InstructionTest, incorrectPred_taken) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test an incorrect prediction is handled correctly - taken is wrong pred = {true, 100 + 0x28}; diff --git a/test/unit/pipeline/DecodeUnitTest.cc b/test/unit/pipeline/DecodeUnitTest.cc index eed1ab60ae..bd89f3c291 100644 --- a/test/unit/pipeline/DecodeUnitTest.cc +++ b/test/unit/pipeline/DecodeUnitTest.cc @@ -53,9 +53,6 @@ TEST_F(PipelineDecodeUnitTest, TickEmpty) { TEST_F(PipelineDecodeUnitTest, Tick) { input.getHeadSlots()[0] = {uopPtr}; - EXPECT_CALL(*uop, checkEarlyBranchMisprediction()) - .WillOnce(Return(std::tuple(false, 0))); - decodeUnit.tick(); // Check result uop is the same as the one provided @@ -67,32 +64,6 @@ TEST_F(PipelineDecodeUnitTest, Tick) { EXPECT_EQ(decodeUnit.getEarlyFlushes(), 0); } -// Tests that the decode unit requests a flush when a non-branch is mispredicted -TEST_F(PipelineDecodeUnitTest, Flush) { - input.getHeadSlots()[0] = {uopPtr}; - - uop->setInstructionAddress(2); - - // Return branch type as unconditional by default - ON_CALL(*uop, getBranchType()) - .WillByDefault(Return(BranchType::Unconditional)); - - EXPECT_CALL(*uop, checkEarlyBranchMisprediction()) - .WillOnce(Return(std::tuple(true, 1))); - 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, - uop->getInstructionId())); - - decodeUnit.tick(); - - // Check that a flush was correctly requested - EXPECT_EQ(decodeUnit.shouldFlush(), true); - EXPECT_EQ(decodeUnit.getFlushAddress(), 1); - EXPECT_EQ(decodeUnit.getEarlyFlushes(), 1); -} - // Tests that PurgeFlushed empties the microOps queue TEST_F(PipelineDecodeUnitTest, purgeFlushed) { input.getHeadSlots()[0] = {uopPtr, uop2Ptr}; diff --git a/test/unit/riscv/InstructionTest.cc b/test/unit/riscv/InstructionTest.cc index 6103cd4f5c..cda72c7fb9 100644 --- a/test/unit/riscv/InstructionTest.cc +++ b/test/unit/riscv/InstructionTest.cc @@ -435,38 +435,6 @@ TEST_F(RiscVInstructionTest, supplyData_dataAbort) { EXPECT_EQ(insn.getException(), InstructionException::DataAbort); } -// Test to check logic around early branch misprediction logic -TEST_F(RiscVInstructionTest, earlyBranchMisprediction) { - // Insn is `div a3, a3, a0` - Instruction insn = Instruction(arch, *divMetadata.get()); - insn.setInstructionAddress(64); - - // Check initial state of an instruction's branch related options - BranchPrediction pred = {false, 0}; - bool matchingPred = (insn.getBranchPrediction() == pred); - EXPECT_TRUE(matchingPred); - EXPECT_FALSE(insn.wasBranchTaken()); - EXPECT_EQ(insn.getBranchAddress(), 0); - EXPECT_EQ(insn.getBranchType(), BranchType::Unknown); - EXPECT_FALSE(insn.isBranch()); - std::tuple tup = {false, insn.getInstructionAddress() + 4}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); - - // Set prediction and ensure expected state changes / outcomes are seen - pred = {true, 0x4848}; - insn.setBranchPrediction(pred); - matchingPred = (insn.getBranchPrediction() == pred); - EXPECT_TRUE(matchingPred); - EXPECT_FALSE(insn.wasBranchTaken()); - EXPECT_EQ(insn.getBranchAddress(), 0); - EXPECT_EQ(insn.getBranchType(), BranchType::Unknown); - // Check logic of `checkEarlyBranchMisprediction` which is different for - // non-branch instructions - EXPECT_FALSE(insn.isBranch()); - tup = {true, insn.getInstructionAddress() + 4}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); -} - // Test that a correct prediction (branch taken) is handled correctly TEST_F(RiscVInstructionTest, correctPred_taken) { // insn is `bgeu a5, a4, -86` @@ -481,8 +449,6 @@ TEST_F(RiscVInstructionTest, correctPred_taken) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test a correct prediction where branch is taken is handled correctly pred = {true, 400 - 86}; @@ -511,8 +477,6 @@ TEST_F(RiscVInstructionTest, correctPred_notTaken) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test a correct prediction where a branch isn't taken is handled correctly // imm operand 0x28 has 4 added implicitly by dissassembler @@ -542,8 +506,6 @@ TEST_F(RiscVInstructionTest, incorrectPred_target) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test an incorrect prediction is handled correctly - target is wrong // imm operand 0x28 has 4 added implicitly by dissassembler @@ -573,8 +535,6 @@ TEST_F(RiscVInstructionTest, incorrectPred_taken) { EXPECT_EQ(insn.getBranchAddress(), 0); EXPECT_EQ(insn.getBranchType(), BranchType::Conditional); EXPECT_TRUE(insn.isBranch()); - std::tuple tup = {false, 0}; - EXPECT_EQ(insn.checkEarlyBranchMisprediction(), tup); // Test an incorrect prediction is handled correctly - taken is wrong // imm operand 0x28 has 4 added implicitly by dissassembler