mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-19 16:42:33 +00:00
The matcher path (generic builders, hand-built, decode->re-encode) resolves an instruction to its encoding form by linearly scanning the forms for its mnemonic and operand-matching each -- the dominant cost on that path. Memoize it: pack (mnemonic, per-operand shape) into a key (immediates folded to the smallest size class they fit, matching imm_matches_inline) and cache key -> form so a repeated instruction shape skips the scan. Direct-mapped, fixed 8192-slot table (64 KB, no allocation). Each slot packs the full 48-bit key and form index into one u64, read/written with relaxed atomics, so concurrent encode() stays safe -- a reader sees a matching key or rescans, never a torn entry. The scan stays the source of truth (a miss runs it and records the result), so the cache is exact. Lookup + scan live in a non-inlined find_form() so they don't bloat encode()'s hot loop and slow the hint path that shares it. (Routing the matcher path through the recipe emit was tried and dropped: it costs the hint path ~1.2-1.5 ns however isolated -- the hot loop is too codegen-sensitive -- while the cache alone is free for the hint path.) Realistic generic-builder mix: matcher ~52 -> ~35 ns/inst (~1.49x); hint path unchanged. Byte-exact across 2282 + idempotent.