Files
Odin/core/rexcode/isa/label_infer.odin
2026-06-14 17:03:19 +01:00

74 lines
2.5 KiB
Odin

package rexcode_isa
// =============================================================================
// LABEL INFERENCE (decoder helper, architecture-independent)
// =============================================================================
//
// Pass 2 of decode: turn the list of branch targets discovered during
// instruction decoding into label definitions, reusing label IDs from a
// caller-supplied relocations array when available (so symbolic names
// from the encoder survive the round trip).
// Branch target discovered while decoding. Each branch operand a
// per-arch decoder produces (RELATIVE-kind operand with a known target
// offset) becomes one of these for pass 2.
Branch_Target :: struct {
inst_idx: u32, // which decoded instruction has the branch
op_idx: u8, // which operand of that instruction is the target
target: u32, // absolute byte offset of the branch target
}
// Resolve branch targets into label definitions.
//
// For each branch target inside the decoded region (target < decoded_end):
// - if a label is already defined at that offset, do nothing;
// - else if `relocs` provides a label_id for that offset (named label
// carried over from the encode side), use that ID;
// - else create a fresh label ID and append it.
//
// label_defs may grow.
//
// Parametric over the caller's relocation type `$R`: the body only reads
// `.offset` and `.label_id`, so any per-arch `Relocation` struct with
// those fields works. Monomorphizes at the call site with no overhead.
infer_labels_from_branches :: proc(
branches: []Branch_Target,
decoded_end: u32,
label_defs: ^[dynamic]Label_Definition,
relocs: []$R,
) {
offset_to_label: map[u32]u32
defer delete(offset_to_label)
for _, id in label_defs {
if label_defs[id] != LABEL_UNDEFINED {
offset_to_label[u32(label_defs[id])] = u32(id)
}
}
relocation_offset_to_label: map[u32]u32
defer delete(relocation_offset_to_label)
for relocation in relocs {
relocation_offset_to_label[relocation.offset] = relocation.label_id
}
for branch in branches {
if branch.target >= decoded_end {
continue
}
if branch.target in offset_to_label {
continue
}
if reloc_id, ok := relocation_offset_to_label[branch.target]; ok {
for u32(len(label_defs)) <= reloc_id {
append(label_defs, LABEL_UNDEFINED)
}
label_defs[reloc_id] = Label_Definition(branch.target)
offset_to_label[branch.target] = reloc_id
} else {
new_id := u32(len(label_defs))
append(label_defs, Label_Definition(branch.target))
offset_to_label[branch.target] = new_id
}
}
}