amd64_cache_check.pl
Independent translation validation for the block-local scalar cache. There are no allocation intervals, slot assignments or eviction plans here. The two streams execute together on symbolic register and home contents; only the three eligible moves may differ, and a load may be absent when its complete result is already in its destination. All other lines match exactly, including flags, failure arguments and control flow.
Ordinary registers have one shared symbolic map: a changed load must prove equality before writing it. Homes have separate reference and actual contents, and each cache register holds a full 64-bit value. Values have independent low/high halves, so a 32-bit read zero-extends its destination without truncating the cached home. Unchanged opaque instructions give their written families fresh, shared symbols.
Before every boundary all homes must agree. Afterward we forget the cache and start with arbitrary common homes/registers. This proves each straight-line region for every possible entry state, including entries from other branches; it does not follow textual fallthrough through a label. Unmentioned/noneligible homes cannot differ because every instruction touching them is unchanged and a boundary. The home map is sparse: untouched homes have a common epoch-tagged default. Boundaries scan only homes written in that region, not the frame.
Metadata is cache_metadata(Setjmp, [home(Offset, Classes), ...]). Every alias's class must be present; unknown is an ineligible class. Placement and complete alias classes are trusted emitter metadata. Unsupported original code and any setjmp permit identity only. Once preflight succeeds, a bad candidate fails, never falls back to identity. Validate a whole function: caching starts only after movq rsp,rbp.
Check disjoint offsets, then derive eligibility from the trusted classes. Duplicate/overlapping homes are not a physical scalar-slot description.
The syntax partitions extra moves from matched instructions: preflight excludes the cache bank everywhere in the original, including addresses.
A fill replaces the next original read, never speculates one. In particular, rbp may exist before stack growth and its overflow check.
The original prologue must establish the frame before any cache use. Later labels can enter another epilogue's live frame, but labels before that prologue cannot open it. No inserted access follows leave/terminal until a label; even an apparently harmless fill-and-spill is forbidden.