use crate::config::BackendKind;
use crate::config::{BranchPredictorKind, Config};
use crate::tests::support::builder::instruction::InstructionBuilder;
use crate::tests::support::harness::TestContext;
const PROGRAM_BASE: u64 = 0x8000_0000;
const ITERATIONS: i32 = 20;
const DONE_REG: usize = 31;
const DONE: u64 = 7;
fn alternating_indirect_jump() -> Vec<u32> {
let i = InstructionBuilder::new;
let nop = i().nop().build();
vec![
i().addi(5, 0, ITERATIONS).build(), i().auipc(6, 0).build(), i().addi(6, 6, 0x1c).build(), i().addi(7, 0, 8).build(), i().jalr(0, 6, 0).build(), nop, nop, nop, nop, i().jal(0, 8).build(), nop, i().xor(6, 6, 7).build(), i().addi(5, 5, -1).build(), i().bne(5, 0, -0x24).build(), i().addi(DONE_REG as u32, 0, DONE as i32).build(),
i().jal(0, 0).build(),
]
}
fn committed_mispredicts(backend: BackendKind) -> u64 {
let mut config = Config::default();
config.pipeline.backend = backend;
config.pipeline.branch_predictor = BranchPredictorKind::GShare;
let mut ctx = TestContext::new_with_config(&config)
.load_program(PROGRAM_BASE, &alternating_indirect_jump());
ctx.run_until(20_000, |ctx| ctx.get_reg(DONE_REG) == DONE).expect("program finished");
let path = ctx.sim.state.cores[0].units.stat_paths.bp.committed_mispredicts;
ctx.sim.state.stats.get(path).unwrap_or(0.0) as u64
}
#[test]
fn a_mispredicted_jump_counts_as_a_committed_misprediction() {
for backend in [BackendKind::InOrder, BackendKind::OutOfOrder] {
let mispredicts = committed_mispredicts(backend);
assert!(
mispredicts >= ITERATIONS as u64 - 2,
"{backend:?}: {mispredicts} committed mispredictions"
);
}
}