mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-19 08:32:33 +00:00
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:
@@ -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`.
|
||||
|
||||
@@ -545,3 +545,30 @@ unpack_operand :: proc(word: u32, enc: Operand_Encoding, ot: Operand_Type) -> Op
|
||||
return op_imm(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (A32 is 4 bytes, Thumb 2; minimum 2).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 2
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -23,8 +23,28 @@ package rexcode_arm32
|
||||
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int { return n * 4 }
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int { return n }
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
instructions: []Instruction,
|
||||
|
||||
@@ -658,3 +658,29 @@ reg_from_field :: #force_inline proc "contextless" (
|
||||
}
|
||||
return Operand{reg = Register(cls | hw), kind = .REGISTER, size = 4}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Exact instruction-count ceiling for `data` (AArch64 instructions are 4 bytes).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4
|
||||
}
|
||||
|
||||
// Typical-case estimate (AArch64 is fixed 4 bytes/instruction, so this is exact).
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -31,8 +31,27 @@ package rexcode_arm64
|
||||
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int { return n * 4 }
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int { return n }
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
instructions: []Instruction,
|
||||
|
||||
@@ -427,3 +427,30 @@ reg_operand :: #force_inline proc "contextless" (r: Register, ot: Operand_Type)
|
||||
}
|
||||
return Operand{reg = r, kind = .REGISTER, size = size}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (MIPS instructions are 4 bytes).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -48,14 +48,29 @@ package rexcode_mips
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
// Upper bound on bytes emitted for `n` instructions.
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n * 4
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
|
||||
// Upper bound on pending relocations for `n` instructions
|
||||
// (each instruction has at most one label-referencing operand).
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -245,3 +245,30 @@ mem_operand :: #force_inline proc "contextless" (addr: u16, ot: Operand_Type) ->
|
||||
size = size,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (shortest instruction is 1 byte).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data)
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 2 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -31,13 +31,27 @@ import "core:rexcode/isa"
|
||||
|
||||
MAX_INST_SIZE :: 7 // HuC6280 block transfer
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n * MAX_INST_SIZE
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int {
|
||||
// BBR/BBS have two operands but only one is a label; cap at one per inst.
|
||||
return n
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
|
||||
@@ -246,3 +246,30 @@ mem_operand_long :: #force_inline proc "contextless" (addr: u32, ot: Operand_Typ
|
||||
size = 3,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (shortest instruction is 1 byte).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data)
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 3 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -24,12 +24,27 @@ import "core:rexcode/isa"
|
||||
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n * MAX_INST_SIZE
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
|
||||
@@ -300,3 +300,30 @@ unpack_operand :: proc(word: u32, enc: Operand_Encoding, ot: Operand_Type) -> Op
|
||||
}
|
||||
return op_imm(0)
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (PowerPC instructions are 4 bytes (prefixed 8); minimum 4).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -23,8 +23,27 @@ package rexcode_ppc
|
||||
|
||||
MAX_INST_SIZE :: 8 // prefixed instructions
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int { return n * MAX_INST_SIZE }
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int { return n }
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
instructions: []Instruction,
|
||||
|
||||
@@ -200,3 +200,30 @@ unpack_operand :: proc(word: u32, enc: Operand_Encoding, ot: Operand_Type) -> Op
|
||||
}
|
||||
return op_imm(0)
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (VLE is 2 or 4 bytes; minimum 2).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 2
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -14,8 +14,27 @@ package rexcode_ppc_vle
|
||||
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int { return n * 4 }
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int { return n }
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
instructions: []Instruction,
|
||||
|
||||
@@ -330,3 +330,30 @@ decode_reg :: #force_inline proc "contextless" (word: u32, shift: u8, ot: Operan
|
||||
reg_operand :: #force_inline proc "contextless" (r: Register) -> Operand {
|
||||
return Operand{reg = r, kind = .REGISTER, size = 4}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (base is 4 bytes, compressed (C) 2; minimum 2).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 2
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -26,11 +26,26 @@ package rexcode_riscv
|
||||
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n * 4
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
|
||||
@@ -252,3 +252,30 @@ decode_gpr :: #force_inline proc "contextless" (word: u32, shift: u8, ot: Operan
|
||||
reg_operand_scalar :: #force_inline proc "contextless" (r: Register, ot: Operand_Type) -> Operand {
|
||||
return Operand{reg = r, kind = .REGISTER, size = 4}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer-Sizing Helpers (let callers pre-size so the decode hot path never
|
||||
// reallocates; allocates no new buffers -- only the caller's arrays grow).
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Instruction-count ceiling for `data` (RSP instructions are 4 bytes).
|
||||
@(require_results)
|
||||
decode_max_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4
|
||||
}
|
||||
|
||||
// Typical-case estimate of the instruction count for `data`.
|
||||
@(require_results)
|
||||
decode_estimate_instruction_count :: #force_inline proc "contextless" (data: []u8) -> int {
|
||||
return len(data) / 4 + 8
|
||||
}
|
||||
|
||||
// Pre-size the caller's decode output arrays for `data` (reserves on top of any
|
||||
// existing elements; nil to skip; exact=true for the ceiling, else the estimate).
|
||||
decode_reserve :: proc(instructions: ^[dynamic]Instruction, inst_info: ^[dynamic]Instruction_Info, label_defs: ^[dynamic]Label_Definition, data: []u8, exact: bool = false) {
|
||||
n := exact ? decode_max_instruction_count(data) : decode_estimate_instruction_count(data)
|
||||
if instructions != nil { reserve(instructions, len(instructions) + n) }
|
||||
if inst_info != nil { reserve(inst_info, len(inst_info) + n) }
|
||||
if label_defs != nil { reserve(label_defs, len(label_defs) + n) }
|
||||
}
|
||||
|
||||
@@ -21,12 +21,27 @@ package rexcode_rsp
|
||||
|
||||
MAX_INST_SIZE :: 4
|
||||
|
||||
encode_max_code_size :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n * 4
|
||||
encode_max_code_size :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions) * MAX_INST_SIZE
|
||||
}
|
||||
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (n: int) -> int {
|
||||
return n
|
||||
encode_max_relocation_count :: #force_inline proc "contextless" (instructions: []Instruction) -> int {
|
||||
return len(instructions)
|
||||
}
|
||||
|
||||
// Pre-size the caller's encode outputs (code grown by length so code[:] is a
|
||||
// valid emit target; relocs reserved by capacity) so the encode hot path never
|
||||
// reallocates. Allocates no new buffers; pass nil to skip either array.
|
||||
encode_reserve :: proc(code: ^[dynamic]u8, relocs: ^[dynamic]Relocation, instructions: []Instruction) {
|
||||
if code != nil {
|
||||
size := encode_max_code_size(instructions)
|
||||
if len(code) < size {
|
||||
resize(code, size)
|
||||
}
|
||||
}
|
||||
if relocs != nil {
|
||||
reserve(relocs, len(relocs) + encode_max_relocation_count(instructions))
|
||||
}
|
||||
}
|
||||
|
||||
encode :: proc(
|
||||
|
||||
Reference in New Issue
Block a user