Summary
A load younger than a taken branch can remain valid in the Load Queue after branch-execute change-flow redirects it away. Although that load never retires, a later older-store address resolution still sees it as a RAW dependency. The false speculation-failure event propagates into ct_lsu_spec_fail_predict and changes the no-speculation predictor state.
I reproduced this on the current OpenC910 main revision b91c90914c19f114d35c8f6b73408eb241ed847c. The OpenC910 RTL was not modified. The architectural self-check passes, as expected for a microarchitectural recovery-state error.
Reproducer
The exact assembly and deterministic VCD checker are available here:
https://gist.github.com/YzhDDDing/cbdf92d06369fc40185b1867f0bf8395
The core sequence enables no-speculation-failure handling, delays an older store address, resolves a taken forward branch, and places three same-address loads on its fall-through path:
csrr x31, mhint
li x30, 0x40000
or x31, x31, x30
csrw mhint, x31
BHT_INV
divu x24, x23, x15
sub x24, x24, x24
add x12, x9, x24
sd x10, 0(x12) # older store, address resolves late
# dependency-spacing instructions are in the full PoC
beq x5, x0, after_wrongpath
ld x13, 0(x9) # wrong path
ld x18, 0(x9) # wrong path
ld x19, 0(x9) # wrong path
after_wrongpath:
sync
ld x16, 0(x9) # correct-path probe
Build lsu_wrongpath_raw.S with smart_run/tests/lib/Makefile, using CPU_ARCH_FLAG_0=c910 CASENAME=lsu_wrongpath_raw FILE=lsu_wrongpath_raw, then run the smart-run testbench with VCD dumping. For the hierarchy used in my replay:
python3 monitor_lsu_wrongpath_raw.py \
test.vcd lsu_wrongpath_raw.obj run_case.report result.json
The checker fails closed if any required signal is missing.
Expected behavior
Once branch recovery kills the fall-through loads, their LQ entries must no longer participate in load/store dependence detection. They must not raise a RAW speculation failure or train future load scheduling.
Observed behavior
The replay produced this ordering (VCD time units are the checker's ps100 units):
| Time |
Event |
| 10493 |
iu_rtu_pipe2_bht_mispred=1 and iu_ifu_chgflw_vld=1 |
| 10509 |
lq_entry_raw_spec_fail=1, lq_st_dc_spec_fail=1, st_dc_spec_fail=1 |
| 10511 |
st_da_sf_no_spec_miss=1 |
| 10517 |
sf_start_success=1 |
| 10519 |
sf_spec_mark=1 |
| 10669 |
the correct-path probe load retires |
None of the wrong-path load PCs retires. The monitor reports predicate=true, no missing signal groups, and wrongpath_retired=[].
RTL analysis
ct_lsu_lq_entry.v clears lq_entry_vld only on commit/pop or rtu_yy_xx_flush; branch execute change-flow is not represented at this validity boundary. The same still-valid entry participates in the store-vs-load RAW comparison.
The result is reduced into lq_st_dc_spec_fail, propagated through store DC/DA, and accepted by ct_lsu_spec_fail_predict.
Suggested fix direction
Make redirect recovery remove or mask younger killed LQ entries before they can contribute to RAW/RAR checks. This needs to be age-qualified; clearing every LQ entry on any frontend redirect could incorrectly discard older correct-path loads. A recovery generation tag, an IID-qualified kill, or a validity mask at the dependence comparator would all preserve that invariant.
It would also be useful to add an assertion that a non-retiring redirect-killed load can never cause lq_st_dc_spec_fail or sf_spec_mark.
Impact
The demonstrated effect is persistent corruption of memory-dependence prediction metadata and unnecessary recovery/no-speculation behavior. This PoC does not demonstrate an architectural result mismatch.
Summary
A load younger than a taken branch can remain valid in the Load Queue after branch-execute change-flow redirects it away. Although that load never retires, a later older-store address resolution still sees it as a RAW dependency. The false speculation-failure event propagates into
ct_lsu_spec_fail_predictand changes the no-speculation predictor state.I reproduced this on the current OpenC910
mainrevisionb91c90914c19f114d35c8f6b73408eb241ed847c. The OpenC910 RTL was not modified. The architectural self-check passes, as expected for a microarchitectural recovery-state error.Reproducer
The exact assembly and deterministic VCD checker are available here:
https://gist.github.com/YzhDDDing/cbdf92d06369fc40185b1867f0bf8395
The core sequence enables no-speculation-failure handling, delays an older store address, resolves a taken forward branch, and places three same-address loads on its fall-through path:
Build
lsu_wrongpath_raw.Swithsmart_run/tests/lib/Makefile, usingCPU_ARCH_FLAG_0=c910 CASENAME=lsu_wrongpath_raw FILE=lsu_wrongpath_raw, then run the smart-run testbench with VCD dumping. For the hierarchy used in my replay:The checker fails closed if any required signal is missing.
Expected behavior
Once branch recovery kills the fall-through loads, their LQ entries must no longer participate in load/store dependence detection. They must not raise a RAW speculation failure or train future load scheduling.
Observed behavior
The replay produced this ordering (VCD time units are the checker's
ps100units):iu_rtu_pipe2_bht_mispred=1andiu_ifu_chgflw_vld=1lq_entry_raw_spec_fail=1,lq_st_dc_spec_fail=1,st_dc_spec_fail=1st_da_sf_no_spec_miss=1sf_start_success=1sf_spec_mark=1None of the wrong-path load PCs retires. The monitor reports
predicate=true, no missing signal groups, andwrongpath_retired=[].RTL analysis
ct_lsu_lq_entry.vclearslq_entry_vldonly on commit/pop orrtu_yy_xx_flush; branch execute change-flow is not represented at this validity boundary. The same still-valid entry participates in the store-vs-load RAW comparison.The result is reduced into
lq_st_dc_spec_fail, propagated through store DC/DA, and accepted byct_lsu_spec_fail_predict.Suggested fix direction
Make redirect recovery remove or mask younger killed LQ entries before they can contribute to RAW/RAR checks. This needs to be age-qualified; clearing every LQ entry on any frontend redirect could incorrectly discard older correct-path loads. A recovery generation tag, an IID-qualified kill, or a validity mask at the dependence comparator would all preserve that invariant.
It would also be useful to add an assertion that a non-retiring redirect-killed load can never cause
lq_st_dc_spec_failorsf_spec_mark.Impact
The demonstrated effect is persistent corruption of memory-dependence prediction metadata and unnecessary recovery/no-speculation behavior. This PoC does not demonstrate an architectural result mismatch.