rexcode: buffer-sizing helpers across all ISAs + naming-contract doc

Roll the encode/decode buffer-sizing helpers (added for x86 in 49787b7de) out
to every other ISA, and document them in the cross-arch naming contract.

Per arch (arm32, arm64, mips, riscv, ppc, ppc_vle, rsp, mos6502, mos65816):
  - encode_max_code_size / encode_max_relocation_count now key off the
    []Instruction slice (were int counts); bodies unchanged (* MAX_INST_SIZE).
  - encode_reserve(code, relocs, instructions): grows the caller's code []u8 by
    length and reserves relocs by capacity; allocates no new buffers.
  - decode_max_instruction_count / decode_estimate_instruction_count: exact
    ceiling and typical estimate, keyed off the min/avg instruction size per
    arch (fixed-4: arm64/mips/ppc/rsp; min-2: arm32/riscv/ppc_vle; min-1: mos).
  - decode_reserve(instructions, inst_info, label_defs, data, exact=false).

docs/cross_arch_design.md: helpers added to the naming contract.

No behavior change to the existing size helpers (signature only). All 10 ISAs
check + test green (x86 2282, arm32 600, arm64 461, mips 281, riscv 154, ppc 31,
ppc_vle 281, rsp 70, mos6502 148, mos65816 53).
This commit is contained in:
Brendan Punsky
2026-06-19 04:10:39 -04:00
committed by Flāvius
parent d2813b978d
commit fae15847a3
19 changed files with 448 additions and 29 deletions

View File

@@ -178,6 +178,32 @@ print/println/aprint/tprint/bprint/fprint/wprint(+ln)(
label_defs: []Label_Definition, tokens=nil, options=nil, label_names=nil)
```
**Buffer-sizing helpers (identical names across arches).** `encode`/`decode`
allocate nothing — the caller owns every buffer. These let the caller pre-size
them so the hot path never reallocates, either as a plain size (caller manages
its own memory) or by growing the caller's own dynamic arrays directly. They
never allocate a fresh buffer; they only grow the caller's arrays, and Odin's
`reserve` no-ops when capacity already suffices.
```odin
// size-only (caller does the resize/reserve)
encode_max_code_size(instructions: []Instruction) -> int // exact code bytes
encode_max_relocation_count(instructions: []Instruction) -> int // exact reloc ceiling
decode_max_instruction_count(data: []u8) -> int // exact instr ceiling
decode_estimate_instruction_count(data: []u8) -> int // typical estimate
// pre-size the caller's dynamic arrays (nil to skip any; reserves on top of existing)
encode_reserve(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction)
decode_reserve(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info,
label_defs: ^[dynamic]Label_Definition, data: []u8, exact := false)
```
> `encode_reserve` grows `code` by *length* (so `code[:]` is a valid emit
> target) and reserves `relocs` by *capacity*. The decode `*_count` pair differs
> per arch by the min/typical instruction size; `decode_reserve(exact=true)`
> uses the guaranteed ceiling, otherwise the lighter estimate. Error arrays grow
> only on the failure path and are intentionally not covered.
**Register/label/print helpers:** `reg_hw reg_class reg_size register_name
mnemonic_to_string label label_forward label_named label_reserve
label_set`.