mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-02 02:03:35 +00:00
Register offset and extended-register offset are one instruction word -- the option field at 15:13 picks LSL / UXTW / SXTW / SXTX -- but only LSL was reachable: no encode form used MEM_EXT, so [Xn, Wm, SXTW #s] had a matcher, a packer, and no way to be asked for. Worse, decoding such a word produced mode REG_OFFSET with a stray extend, which re-encoded as LSL -- a silent corruption round-trip. The one MEM_REG form now serves both modes, the way the RM slot takes plain and shifted registers: the matcher accepts EXT_REG_OFFSET and checks the index width against the extend (UXTW/SXTW take Wm, UXTX/SXTX take Xm, the byte/half extends match nothing -- and a REG_OFFSET index must now be an X register), the OFFSET_REG packer writes option from the operand's mode, and the decoder derives the mode from option rather than from which form matched. MEM_EXT/OFFSET_EXT stay in their enums -- the values are baked into the table blobs -- marked subsumed. Also fixed while there: the decoder stored the raw S bit as the shift amount, so LDR X0, [X1, X2, LSL #3] decoded -- and printed -- as LSL #1. The amount is log2 of the transfer size, recovered from size(31:30) and, for SIMD, opc<1>(23). The one thing Memory cannot represent is a byte access with an explicit #0 (S=1, amount 0); it decodes as no amount. New pipeline tests: ten llvm-mc golden words across the extends and widths, decode/print round-trips matching llvm's canonical spelling, the LSL amount, and four malformed-operand rejections. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFeLCDKi5kRMtHrskUaRfw