fix(cpu): P1 atomicity sweep — invalidate_for_write at all store sites

Implements PPCBUG-107 cascade fix: every store opcode in the interpreter
now calls ReservationTable::invalidate_for_write(ea) when a reservation
table is active and at least one thread holds a reservation. This restores
correct lwarx/stwcx. LL/SC semantics under --parallel --reservations-table.

Batches merged:
  PPCBUG-107,140-144: stw/stwu/stwx/stwux/stwbrx
  PPCBUG-130,150:     stb/stbu/stbx/stbux/sth/sthu/sthx/sthux/sthbrx/std/stdu/stdx/stdux/stdbrx
  PPCBUG-160,167:     stmw/stswi/stswx + all FP stores (stfs/stfd families)
  PPCBUG-511-514:     16 VMX stores (stvx/stvxl/stvebx/stvehx/stvewx/stvlx/stvrx families)
  PPCBUG-151:         stwcx./stdcx. width discriminator (reservation_width: u8 in PpcContext)
  PPCBUG-108:         debug_assert + doc on legacy single-context reservation path
  Review fixes:       stswi/stswx two-line guard; dcbz/dcbz128 guards added (missed in audit)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-01 20:47:49 +02:00
2 changed files with 713 additions and 3 deletions

View File

@@ -101,6 +101,12 @@ pub struct PpcContext {
pub reserved_line: u32,
pub reserved_val: u64,
pub has_reservation: bool,
/// PPCBUG-151 — width of the active reservation: 4 = `lwarx` (word),
/// 8 = `ldarx` (doubleword), 0 = no reservation. `stwcx.` requires
/// width==4; `stdcx.` requires width==8. Cross-width pairs fail
/// deterministically with CR0.EQ=0. Cleared alongside `has_reservation`
/// on every `stwcx.`/`stdcx.` exit (success or failure).
pub reservation_width: u8,
/// M3.7 — generation stamp returned by [`crate::ReservationTable::reserve`]
/// at the most recent `lwarx`/`ldarx`. Paired with `reserved_line`;
/// `stwcx.`/`stdcx.` pass this back to `try_commit`. Meaningful only
@@ -159,6 +165,7 @@ impl PpcContext {
reserved_line: 0,
reserved_val: 0,
has_reservation: false,
reservation_width: 0,
reserved_generation: 0,
reservation_table: None,
hw_id: 0,

File diff suppressed because it is too large Load Diff