From 2e8d3b9e104fe7df4227b8273917c72fedbf2e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C4=81vius?= Date: Mon, 3 Aug 2026 20:51:55 -0400 Subject: [PATCH] =?UTF-8?q?rexcode/isa:=20display-side=20label=20naming=20?= =?UTF-8?q?=E2=80=94=20address=20order,=20offset-keyed=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Internal label ids are allocation-order handles: the encoder's creation order, or the decoder's branch-DISCOVERY order (a loop's latch names the header before an earlier forward target). Printing labels by raw id leaked that accident into listings — label numbers appeared out of order down the page — and the printers' `label_names: ^map[u32]string` keyed the caller's names by those synthesized ids, which a decode consumer cannot know without re-deriving them (the practical result: naming "label 0" could caption a random interior branch target). Naming is now derived at the presentation seam, shared by every ISA (`isa.Label_Display` in isa/print.odin): - display numbers are assigned in ASCENDING ADDRESS order, so a listing reads L0, L1, L2 … top to bottom regardless of id allocation; - caller names are keyed by BYTE OFFSET (`isa.Label_Names`, with a `distinct` Label_Offset key so an id-keyed map from the old contract fails to compile instead of silently mis-naming); - a named offset is guaranteed a label row even when no Label_Definition points at it — `names[0] = "factorial"` heads a function's listing. All ten ISA printers (x86, mips, rsp, arm32, arm64, riscv, ppc, ppc_vle, mos6502, mos65816) drop their per-printer offset_to_label maps and write_label helpers for the shared display; each arch re-exports Label_Offset/Label_Names beside Label_Definition. En route this fixes an arm32/ppc/ppc_vle bug where passing ANY names map suppressed the default L label rows for unnamed labels. Decode-side id assignment is untouched: the reloc round-trip contract (encoder ids surviving decode) and the sparse-id padding it relies on stay exactly as they were. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Riok9vMpkLmo78wsVKJHhz --- core/rexcode/doc.odin | 6 +- core/rexcode/isa/arm32/encoding_types.odin | 2 + core/rexcode/isa/arm32/printer.odin | 69 +++++------ core/rexcode/isa/arm64/encoding_types.odin | 2 + core/rexcode/isa/arm64/printer.odin | 77 +++++-------- core/rexcode/isa/mips/encoding_types.odin | 2 + core/rexcode/isa/mips/printer.odin | 79 +++++-------- core/rexcode/isa/mips/tests/print_smoke.odin | 4 +- core/rexcode/isa/mos6502/encoding_types.odin | 2 + core/rexcode/isa/mos6502/printer.odin | 73 +++++------- .../isa/mos6502/tests/pipeline_smoke.odin | 4 +- core/rexcode/isa/mos65816/encoding_types.odin | 2 + core/rexcode/isa/mos65816/printer.odin | 73 +++++------- core/rexcode/isa/ppc/encoding_types.odin | 2 + core/rexcode/isa/ppc/printer.odin | 70 +++++------- core/rexcode/isa/ppc_vle/encoding_types.odin | 2 + core/rexcode/isa/ppc_vle/printer.odin | 70 +++++------- core/rexcode/isa/print.odin | 108 ++++++++++++++++++ core/rexcode/isa/riscv/encoding_types.odin | 2 + core/rexcode/isa/riscv/printer.odin | 75 +++++------- core/rexcode/isa/rsp/encoding_types.odin | 2 + core/rexcode/isa/rsp/printer.odin | 77 +++++-------- core/rexcode/isa/x86/labels.odin | 2 + core/rexcode/isa/x86/printer.odin | 87 ++++++-------- core/rexcode/isa/x86/tests/test.odin | 9 +- 25 files changed, 424 insertions(+), 477 deletions(-) diff --git a/core/rexcode/doc.odin b/core/rexcode/doc.odin index b58fd1e6a..4fbeb29fa 100644 --- a/core/rexcode/doc.odin +++ b/core/rexcode/doc.odin @@ -142,9 +142,9 @@ x86.label_set(&lm, "done", &instructions) result := x86.encode(instructions[:], lm.labels[:], code[:], &relocs, &errors) // Printer wants id→name; Label_Map stores name→id, so invert once. -id_to_name := make(map[u32]string, len(lm.names), context.temp_allocator) -for name, id in lm.names { id_to_name[id] = name } -x86.print(decoded_insts[:], decoded_info[:], lm.labels[:], label_names = &id_to_name) +names := make(x86.Label_Names, len(lm.names), context.temp_allocator) // BYTE OFFSET -> name +for name, id in lm.names { names[x86.Label_Offset(u32(lm.labels[id]))] = name } +x86.print(decoded_insts[:], decoded_info[:], lm.labels[:], label_names = &names) ``` ## Driver script (`build.lua`) diff --git a/core/rexcode/isa/arm32/encoding_types.odin b/core/rexcode/isa/arm32/encoding_types.odin index 57e780397..671389265 100644 --- a/core/rexcode/isa/arm32/encoding_types.odin +++ b/core/rexcode/isa/arm32/encoding_types.odin @@ -54,6 +54,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map diff --git a/core/rexcode/isa/arm32/printer.odin b/core/rexcode/isa/arm32/printer.odin index 2cdf97ac1..375260224 100644 --- a/core/rexcode/isa/arm32/printer.odin +++ b/core/rexcode/isa/arm32/printer.odin @@ -70,7 +70,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -78,13 +78,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. 0 { strings.write_string(sb, ", ") } - write_operand(sb, &inst.ops[k], inst, offset, &offset_to_label, label_names, opts) + write_operand(sb, &inst.ops[k], inst, offset, &display, opts) } } strings.write_string(sb, "\n") @@ -269,7 +261,7 @@ sbprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sbprint(sb, instructions, inst_info, label_defs, tokens, options, label_names) strings.write_byte(sb, '\n') @@ -281,7 +273,7 @@ sbprintln :: proc( print :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -290,7 +282,7 @@ print :: proc( println :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -299,7 +291,7 @@ println :: proc( aprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -309,7 +301,7 @@ aprint :: proc( aprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -319,7 +311,7 @@ aprintln :: proc( tprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -328,7 +320,7 @@ tprint :: proc( tprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -338,7 +330,7 @@ tprintln :: proc( bprint :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -348,7 +340,7 @@ bprint :: proc( bprintln :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -358,7 +350,7 @@ bprintln :: proc( fprint :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -368,7 +360,7 @@ fprint :: proc( fprintln :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -378,7 +370,7 @@ fprintln :: proc( wprint :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -388,7 +380,7 @@ wprint :: proc( wprintln :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -460,8 +452,7 @@ write_operand :: proc( op: ^Operand, inst: ^Instruction, offset: u32, - offset_to_label: ^map[u32]u32, - label_names: ^map[u32]string, + display: ^isa.Label_Display, opts: ^Print_Options, ) { switch op.kind { @@ -482,14 +473,8 @@ write_operand :: proc( case .RELATIVE: // Resolve to label if possible target := u32(i64(offset) + op.relative) - if id, ok := offset_to_label[target]; ok { - if label_names != nil { - if name, has := label_names[id]; has { - strings.write_string(sb, name) - return - } - } - fmt.sbprintf(sb, "L%d", id) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { // raw absolute fmt.sbprintf(sb, "0x%x", target) diff --git a/core/rexcode/isa/arm64/encoding_types.odin b/core/rexcode/isa/arm64/encoding_types.odin index 47269bc1b..e2c4a29ec 100644 --- a/core/rexcode/isa/arm64/encoding_types.odin +++ b/core/rexcode/isa/arm64/encoding_types.odin @@ -40,6 +40,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map diff --git a/core/rexcode/isa/arm64/printer.odin b/core/rexcode/isa/arm64/printer.odin index c5a2141f7..df7975f0c 100644 --- a/core/rexcode/isa/arm64/printer.odin +++ b/core/rexcode/isa/arm64/printer.odin @@ -79,7 +79,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -87,13 +87,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. string { sb := strings.builder_make(allocator) @@ -184,7 +183,7 @@ aprint :: proc( aprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -194,7 +193,7 @@ aprintln :: proc( tprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -203,7 +202,7 @@ tprint :: proc( tprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -213,7 +212,7 @@ tprintln :: proc( bprint :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -223,7 +222,7 @@ bprint :: proc( bprintln :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -233,7 +232,7 @@ bprintln :: proc( fprint :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -243,7 +242,7 @@ fprint :: proc( fprintln :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -253,7 +252,7 @@ fprintln :: proc( wprint :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -263,7 +262,7 @@ wprint :: proc( wprintln :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -390,11 +389,10 @@ write_register :: proc(sb: ^strings.Builder, r: Register, uppercase: bool) { @(private="file") write_operand :: proc( - sb: ^strings.Builder, - op: ^Operand, - offset_to_label: map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + sb: ^strings.Builder, + op: ^Operand, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { switch op.kind { case .NONE: @@ -449,8 +447,8 @@ write_operand :: proc( case .RELATIVE: target := u32(op.relative) - if id, has := offset_to_label[target]; has { - write_label(sb, id, label_names, opts) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { isa.print_hex(sb, u64(target), opts) } @@ -512,23 +510,6 @@ write_memory :: proc(sb: ^strings.Builder, m: Memory, opts: ^Print_Options) { } } -@(private="file") -write_label :: proc( - sb: ^strings.Builder, - label_id: u32, - label_names: ^map[u32]string, - opts: ^Print_Options, -) { - if label_names != nil { - if name, has := label_names^[label_id]; has { - strings.write_string(sb, name) - return - } - } - strings.write_string(sb, opts.label_prefix) - write_decimal_u32(sb, label_id) -} - @(private="file") write_decimal_u32 :: proc(sb: ^strings.Builder, v: u32) { if v == 0 { strings.write_byte(sb, '0'); return } diff --git a/core/rexcode/isa/mips/encoding_types.odin b/core/rexcode/isa/mips/encoding_types.odin index ad3a2c13c..e46a9c4ea 100644 --- a/core/rexcode/isa/mips/encoding_types.odin +++ b/core/rexcode/isa/mips/encoding_types.odin @@ -38,6 +38,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map // Relocation and Relocation_Type live in reloc.odin (per-arch by design). diff --git a/core/rexcode/isa/mips/printer.odin b/core/rexcode/isa/mips/printer.odin index b51b14095..3fb1f2114 100644 --- a/core/rexcode/isa/mips/printer.odin +++ b/core/rexcode/isa/mips/printer.odin @@ -74,7 +74,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -83,14 +83,11 @@ sbprint :: proc( opts = &defaults } - // Offset -> label_id index (single linear pass over label_defs). - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. string { sb := strings.builder_make(allocator) @@ -193,7 +190,7 @@ aprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -207,7 +204,7 @@ tprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -220,7 +217,7 @@ tprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -234,7 +231,7 @@ bprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -248,7 +245,7 @@ bprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -262,7 +259,7 @@ fprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -276,7 +273,7 @@ fprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -290,7 +287,7 @@ wprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -304,7 +301,7 @@ wprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -404,11 +401,10 @@ write_register :: proc(sb: ^strings.Builder, r: Register, uppercase: bool) { @(private="file") write_operand :: proc( - sb: ^strings.Builder, - op: ^Operand, - offset_to_label: map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + sb: ^strings.Builder, + op: ^Operand, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { switch op.kind { case .NONE: @@ -428,8 +424,8 @@ write_operand :: proc( case .RELATIVE: target := u32(op.relative) - if id, has := offset_to_label[target]; has { - write_label(sb, id, label_names, opts) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { // No label discovered at this target -- fall back to absolute hex. isa.print_hex(sb, u64(target), opts) @@ -437,23 +433,6 @@ write_operand :: proc( } } -@(private="file") -write_label :: proc( - sb: ^strings.Builder, - label_id: u32, - label_names: ^map[u32]string, - opts: ^Print_Options, -) { - if label_names != nil { - if name, has := label_names^[label_id]; has { - strings.write_string(sb, name) - return - } - } - strings.write_string(sb, opts.label_prefix) - write_decimal_u32(sb, label_id) -} - @(private="file") write_decimal_u32 :: proc(sb: ^strings.Builder, v: u32) { if v == 0 { diff --git a/core/rexcode/isa/mips/tests/print_smoke.odin b/core/rexcode/isa/mips/tests/print_smoke.odin index 336ae5fbb..2a27002d5 100644 --- a/core/rexcode/isa/mips/tests/print_smoke.odin +++ b/core/rexcode/isa/mips/tests/print_smoke.odin @@ -173,9 +173,9 @@ run_printer_tests :: proc() { clear(&errors) mips.decode(code[:byte_count], nil, &dec_insts, &dec_info, &dec_labels, &errors) - names: map[u32]string + names: mips.Label_Names // keyed by BYTE OFFSET defer delete(names) - names[0] = "loop" + names[mips.Label_Offset(0)] = "loop" out := mips.aprint(dec_insts[:], dec_info[:], dec_labels[:], nil, nil, &names, context.temp_allocator) pcheck("Named label", diff --git a/core/rexcode/isa/mos6502/encoding_types.odin b/core/rexcode/isa/mos6502/encoding_types.odin index 444bcd74f..5dca155a1 100644 --- a/core/rexcode/isa/mos6502/encoding_types.odin +++ b/core/rexcode/isa/mos6502/encoding_types.odin @@ -30,6 +30,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map // Relocation and Relocation_Type live in reloc.odin (per-arch by design). diff --git a/core/rexcode/isa/mos6502/printer.odin b/core/rexcode/isa/mos6502/printer.odin index f2a5020ee..8786420e1 100644 --- a/core/rexcode/isa/mos6502/printer.odin +++ b/core/rexcode/isa/mos6502/printer.odin @@ -61,7 +61,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -69,13 +69,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. string { sb := strings.builder_make(allocator) @@ -161,7 +160,7 @@ aprint :: proc( aprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -171,7 +170,7 @@ aprintln :: proc( tprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -180,7 +179,7 @@ tprint :: proc( tprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -190,7 +189,7 @@ tprintln :: proc( bprint :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -200,7 +199,7 @@ bprint :: proc( bprintln :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -210,7 +209,7 @@ bprintln :: proc( fprint :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -220,7 +219,7 @@ fprint :: proc( fprintln :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -230,7 +229,7 @@ fprintln :: proc( wprint :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -240,7 +239,7 @@ wprint :: proc( wprintln :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -277,9 +276,8 @@ write_mnemonic :: proc(sb: ^strings.Builder, m: Mnemonic, uppercase: bool) { write_operand :: proc( sb: ^strings.Builder, op: ^Operand, - offset_to_label: map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { switch op.kind { case .NONE: @@ -297,8 +295,8 @@ write_operand :: proc( case .RELATIVE: target := u32(op.relative) - if id, has := offset_to_label[target]; has { - write_label(sb, id, label_names, opts) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { // Fall back to absolute hex when the target isn't a known label. // Use the operand size to decide width: size=1 -> $XX, size=2 -> $XXXX. @@ -379,23 +377,6 @@ write_hex_value :: proc(sb: ^strings.Builder, v: u64, size: u8) { } } -@(private="file") -write_label :: proc( - sb: ^strings.Builder, - label_id: u32, - label_names: ^map[u32]string, - opts: ^Print_Options, -) { - if label_names != nil { - if name, has := label_names^[label_id]; has { - strings.write_string(sb, name) - return - } - } - strings.write_string(sb, opts.label_prefix) - write_decimal_u32(sb, label_id) -} - @(private="file") write_decimal_u32 :: proc(sb: ^strings.Builder, v: u32) { if v == 0 { strings.write_byte(sb, '0'); return } diff --git a/core/rexcode/isa/mos6502/tests/pipeline_smoke.odin b/core/rexcode/isa/mos6502/tests/pipeline_smoke.odin index 03fe27b76..5f249d205 100644 --- a/core/rexcode/isa/mos6502/tests/pipeline_smoke.odin +++ b/core/rexcode/isa/mos6502/tests/pipeline_smoke.odin @@ -248,9 +248,9 @@ run_pipeline_tests :: proc() { m.decode(code[:byte_count], nil, &d_insts, &d_info, &d_labels, &errors, cpu = .CMOS_65C02) - names: map[u32]string + names: m.Label_Names // keyed by BYTE OFFSET defer delete(names) - names[0] = "start" + names[m.Label_Offset(0)] = "start" text := m.aprint(d_insts[:], d_info[:], d_labels[:], nil, nil, &names, context.temp_allocator) diff --git a/core/rexcode/isa/mos65816/encoding_types.odin b/core/rexcode/isa/mos65816/encoding_types.odin index 8f3c22c66..676a1fcfd 100644 --- a/core/rexcode/isa/mos65816/encoding_types.odin +++ b/core/rexcode/isa/mos65816/encoding_types.odin @@ -33,6 +33,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map diff --git a/core/rexcode/isa/mos65816/printer.odin b/core/rexcode/isa/mos65816/printer.odin index 61cd358c6..273887eed 100644 --- a/core/rexcode/isa/mos65816/printer.odin +++ b/core/rexcode/isa/mos65816/printer.odin @@ -60,7 +60,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -68,13 +68,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. string { sb := strings.builder_make(allocator) @@ -168,7 +167,7 @@ aprint :: proc( aprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -178,7 +177,7 @@ aprintln :: proc( tprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -187,7 +186,7 @@ tprint :: proc( tprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -197,7 +196,7 @@ tprintln :: proc( bprint :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -207,7 +206,7 @@ bprint :: proc( bprintln :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -217,7 +216,7 @@ bprintln :: proc( fprint :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -227,7 +226,7 @@ fprint :: proc( fprintln :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -237,7 +236,7 @@ fprintln :: proc( wprint :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -247,7 +246,7 @@ wprint :: proc( wprintln :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -276,9 +275,8 @@ write_mnemonic :: proc(sb: ^strings.Builder, m: Mnemonic, uppercase: bool) { write_operand :: proc( sb: ^strings.Builder, op: ^Operand, - offset_to_label: map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { switch op.kind { case .NONE: @@ -295,8 +293,8 @@ write_operand :: proc( case .RELATIVE: target := u32(op.relative) - if id, has := offset_to_label[target]; has { - write_label(sb, id, label_names, opts) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { write_hex_value(sb, u64(target), op.size) } @@ -395,23 +393,6 @@ write_hex_value :: proc(sb: ^strings.Builder, v: u64, size: u8) { } } -@(private="file") -write_label :: proc( - sb: ^strings.Builder, - label_id: u32, - label_names: ^map[u32]string, - opts: ^Print_Options, -) { - if label_names != nil { - if name, has := label_names^[label_id]; has { - strings.write_string(sb, name) - return - } - } - strings.write_string(sb, opts.label_prefix) - write_decimal_u32(sb, label_id) -} - @(private="file") write_decimal_u32 :: proc(sb: ^strings.Builder, v: u32) { if v == 0 { strings.write_byte(sb, '0'); return } diff --git a/core/rexcode/isa/ppc/encoding_types.odin b/core/rexcode/isa/ppc/encoding_types.odin index 2906861cb..a47a2f9b6 100644 --- a/core/rexcode/isa/ppc/encoding_types.odin +++ b/core/rexcode/isa/ppc/encoding_types.odin @@ -70,6 +70,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map diff --git a/core/rexcode/isa/ppc/printer.odin b/core/rexcode/isa/ppc/printer.odin index 3105b7b43..414c070ee 100644 --- a/core/rexcode/isa/ppc/printer.odin +++ b/core/rexcode/isa/ppc/printer.odin @@ -57,7 +57,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -65,13 +65,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. 0 { strings.write_string(sb, ", ") } - write_operand(sb, &inst.ops[k], offset, &offset_to_label, label_names, opts) + write_operand(sb, &inst.ops[k], offset, &display, opts) } } strings.write_string(sb, "\n") @@ -121,7 +114,7 @@ sbprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sbprint(sb, instructions, inst_info, label_defs, tokens, options, label_names) strings.write_byte(sb, '\n') @@ -137,7 +130,7 @@ print :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -150,7 +143,7 @@ println :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -163,7 +156,7 @@ aprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -177,7 +170,7 @@ aprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -191,7 +184,7 @@ tprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -204,7 +197,7 @@ tprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -218,7 +211,7 @@ bprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -232,7 +225,7 @@ bprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -246,7 +239,7 @@ fprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -260,7 +253,7 @@ fprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -274,7 +267,7 @@ wprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -288,7 +281,7 @@ wprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -361,9 +354,8 @@ write_operand :: proc( sb: ^strings.Builder, op: ^Operand, inst_offset: u32, - offset_to_label: ^map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { #partial switch op.kind { case .NONE: @@ -393,14 +385,8 @@ write_operand :: proc( // (post-decode) or an absolute label target if a label_defs roundtrip // has resolved it. Prefer label form when we can match the target. target := u32(i32(inst_offset) + i32(op.relative)) - if id, ok := offset_to_label[target]; ok { - if label_names != nil { - if name, has := label_names[id]; has { - strings.write_string(sb, name) - return - } - } - fmt.sbprintf(sb, "L%d", id) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { // Print as PC-relative offset if op.relative >= 0 { diff --git a/core/rexcode/isa/ppc_vle/encoding_types.odin b/core/rexcode/isa/ppc_vle/encoding_types.odin index 87754a7e3..2501b13ef 100644 --- a/core/rexcode/isa/ppc_vle/encoding_types.odin +++ b/core/rexcode/isa/ppc_vle/encoding_types.odin @@ -20,6 +20,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map diff --git a/core/rexcode/isa/ppc_vle/printer.odin b/core/rexcode/isa/ppc_vle/printer.odin index d2896fb30..1b8fc1448 100644 --- a/core/rexcode/isa/ppc_vle/printer.odin +++ b/core/rexcode/isa/ppc_vle/printer.odin @@ -35,7 +35,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -43,13 +43,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. 0 { strings.write_string(sb, ", ") } - write_operand(sb, &inst.ops[k], offset, &offset_to_label, label_names, opts) + write_operand(sb, &inst.ops[k], offset, &display, opts) } } strings.write_string(sb, "\n") @@ -99,7 +92,7 @@ sbprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sbprint(sb, instructions, inst_info, label_defs, tokens, options, label_names) strings.write_byte(sb, '\n') @@ -115,7 +108,7 @@ print :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -128,7 +121,7 @@ println :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -141,7 +134,7 @@ aprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -155,7 +148,7 @@ aprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -169,7 +162,7 @@ tprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -182,7 +175,7 @@ tprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -196,7 +189,7 @@ bprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -210,7 +203,7 @@ bprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -224,7 +217,7 @@ fprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -238,7 +231,7 @@ fprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -252,7 +245,7 @@ wprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -266,7 +259,7 @@ wprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -369,9 +362,8 @@ write_operand :: proc( sb: ^strings.Builder, op: ^Operand, inst_offset: u32, - offset_to_label: ^map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { #partial switch op.kind { case .NONE: // skip @@ -389,14 +381,8 @@ write_operand :: proc( } case .RELATIVE: target := u32(i32(inst_offset) + i32(op.relative)) - if id, ok := offset_to_label[target]; ok { - if label_names != nil { - if name, has := label_names[id]; has { - strings.write_string(sb, name) - return - } - } - fmt.sbprintf(sb, "L%d", id) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { if op.relative >= 0 { fmt.sbprintf(sb, ".+%d", op.relative) diff --git a/core/rexcode/isa/print.odin b/core/rexcode/isa/print.odin index 90d4b7f56..8214cdbb6 100644 --- a/core/rexcode/isa/print.odin +++ b/core/rexcode/isa/print.odin @@ -137,3 +137,111 @@ print_decimal :: proc(sb: ^strings.Builder, value: u32) { strings.write_byte(sb, buf[j]) } } + +// ----------------------------------------------------------------------------- +// Label display (presentation-side naming) +// ----------------------------------------------------------------------------- +// +// Internal label ids are allocation-order handles — the encoder's creation +// order, or the decoder's branch-DISCOVERY order (a loop's latch names the +// header before an earlier forward target). That order is an accident as far +// as a listing is concerned: naming labels by raw id makes the numbers appear +// out of order down the page. Display naming is therefore derived HERE, once +// per print call, independent of the ids: +// +// - every DEFINED label offset gets a display number in ASCENDING ADDRESS +// order, so a listing reads L0, L1, L2 … top to bottom; +// - the caller may name any BYTE OFFSET via `Label_Names` +// (`names[0] = "factorial"` heads the listing with the function name) — +// a named offset is displayable even when no Label_Definition points at +// it, since nothing need branch to a function's entry. +// +// `Label_Offset` is a distinct type so a map keyed by the OLD contract +// (internal label ids) fails to compile instead of silently mis-naming. + +Label_Offset :: distinct u32 + +// Caller-supplied display names, keyed by byte offset into the printed region. +Label_Names :: map[Label_Offset]string + +// Per-print-call display state: the sorted set of displayable label offsets +// (display number = index) plus the caller's names. +Label_Display :: struct { + offsets: [dynamic]u32, // ascending; a label's display number is its index here + names: ^Label_Names, // byte-offset-keyed caller names (nil = none) +} + +label_display_init :: proc(display: ^Label_Display, label_defs: []Label_Definition, names: ^Label_Names, allocator := context.allocator) { + display.names = names + display.offsets = make([dynamic]u32, 0, len(label_defs), allocator) + insert_sorted :: proc(offsets: ^[dynamic]u32, offset: u32) { + lo, hi := 0, len(offsets) + for lo < hi { + mid := (lo + hi) / 2 + if offsets[mid] < offset { + lo = mid + 1 + } else { + hi = mid + } + } + if lo < len(offsets) && offsets[lo] == offset { + return // already displayable + } + append(offsets, 0) + copy(offsets[lo + 1:], offsets[lo:]) + offsets[lo] = offset + } + for definition in label_defs { + if definition == LABEL_UNDEFINED do continue + insert_sorted(&display.offsets, u32(definition)) + } + if names != nil { + for offset in names^ { + insert_sorted(&display.offsets, u32(offset)) + } + } +} + +label_display_destroy :: proc(display: ^Label_Display) { + delete(display.offsets) +} + +// Is there a displayable label at `offset` (a definition, or a caller-named offset)? +label_display_at :: proc(display: ^Label_Display, offset: u32) -> bool { + _, found := label_display_rank(display, offset) + return found +} + +// The display number of the label at `offset` (its rank in address order). +label_display_rank :: proc(display: ^Label_Display, offset: u32) -> (rank: int, found: bool) { + lo, hi := 0, len(display.offsets) + for lo < hi { + mid := (lo + hi) / 2 + if display.offsets[mid] < offset { + lo = mid + 1 + } else { + hi = mid + } + } + if lo < len(display.offsets) && display.offsets[lo] == offset { + return lo, true + } + return 0, false +} + +// Write the display name for the label at `offset`: the caller's name for that +// offset if one was supplied, else `` with the address-ordered rank. +label_display_write :: proc(display: ^Label_Display, sb: ^strings.Builder, offset: u32, prefix: string) { + if display.names != nil { + if name, has := display.names^[Label_Offset(offset)]; has { + strings.write_string(sb, name) + return + } + } + rank, found := label_display_rank(display, offset) + if !found { + rank = 0 // an undisplayable offset never reaches here from the printers; be lenient + } + strings.write_string(sb, prefix) + print_decimal(sb, u32(rank)) +} diff --git a/core/rexcode/isa/riscv/encoding_types.odin b/core/rexcode/isa/riscv/encoding_types.odin index 7c3cf21b0..a89151ba4 100644 --- a/core/rexcode/isa/riscv/encoding_types.odin +++ b/core/rexcode/isa/riscv/encoding_types.odin @@ -34,6 +34,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map diff --git a/core/rexcode/isa/riscv/printer.odin b/core/rexcode/isa/riscv/printer.odin index 9bbdea3a9..fe5162e61 100644 --- a/core/rexcode/isa/riscv/printer.odin +++ b/core/rexcode/isa/riscv/printer.odin @@ -77,7 +77,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -85,13 +85,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. string { sb := strings.builder_make(allocator) @@ -175,7 +174,7 @@ aprint :: proc( aprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -185,7 +184,7 @@ aprintln :: proc( tprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -194,7 +193,7 @@ tprint :: proc( tprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -204,7 +203,7 @@ tprintln :: proc( bprint :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -214,7 +213,7 @@ bprint :: proc( bprintln :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -224,7 +223,7 @@ bprintln :: proc( fprint :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -234,7 +233,7 @@ fprint :: proc( fprintln :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -244,7 +243,7 @@ fprintln :: proc( wprint :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -254,7 +253,7 @@ wprint :: proc( wprintln :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -308,10 +307,9 @@ write_register :: proc(sb: ^strings.Builder, r: Register, uppercase: bool) { write_operand :: proc( sb: ^strings.Builder, op: ^Operand, - mnemonic: Mnemonic, - offset_to_label: map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + mnemonic: Mnemonic, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { switch op.kind { case .NONE: @@ -335,31 +333,14 @@ write_operand :: proc( case .RELATIVE: target := u32(op.relative) - if id, has := offset_to_label[target]; has { - write_label(sb, id, label_names, opts) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { isa.print_hex(sb, u64(target), opts) } } } -@(private="file") -write_label :: proc( - sb: ^strings.Builder, - label_id: u32, - label_names: ^map[u32]string, - opts: ^Print_Options, -) { - if label_names != nil { - if name, has := label_names^[label_id]; has { - strings.write_string(sb, name) - return - } - } - strings.write_string(sb, opts.label_prefix) - write_decimal_u32(sb, label_id) -} - @(private="file") write_decimal_u32 :: proc(sb: ^strings.Builder, v: u32) { if v == 0 { strings.write_byte(sb, '0'); return } diff --git a/core/rexcode/isa/rsp/encoding_types.odin b/core/rexcode/isa/rsp/encoding_types.odin index e6b48c586..6a4c41c13 100644 --- a/core/rexcode/isa/rsp/encoding_types.odin +++ b/core/rexcode/isa/rsp/encoding_types.odin @@ -35,6 +35,8 @@ import "core:rexcode/isa" Error :: isa.Error Error_Code :: isa.Error_Code Label_Definition :: isa.Label_Definition +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map // Relocation and Relocation_Type live in reloc.odin (per-arch by design). diff --git a/core/rexcode/isa/rsp/printer.odin b/core/rexcode/isa/rsp/printer.odin index 7b4c4499c..508fa1003 100644 --- a/core/rexcode/isa/rsp/printer.odin +++ b/core/rexcode/isa/rsp/printer.odin @@ -72,7 +72,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^isa.Label_Names = nil, ) { opts := options if opts == nil { @@ -80,13 +80,11 @@ sbprint :: proc( opts = &defaults } - offset_to_label: map[u32]u32 - defer delete(offset_to_label) - for ld, id in label_defs { - if ld != LABEL_UNDEFINED { - offset_to_label[u32(ld)] = u32(id) - } - } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) for i in 0.. string { sb := strings.builder_make(allocator) @@ -172,7 +171,7 @@ aprint :: proc( aprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -182,7 +181,7 @@ aprintln :: proc( tprint :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -191,7 +190,7 @@ tprint :: proc( tprintln :: proc( instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -201,7 +200,7 @@ tprintln :: proc( bprint :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -211,7 +210,7 @@ bprint :: proc( bprintln :: proc( buf: []u8, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) -> string { sb := strings.builder_from_bytes(buf) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -221,7 +220,7 @@ bprintln :: proc( fprint :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -231,7 +230,7 @@ fprint :: proc( fprintln :: proc( fd: ^os.File, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -241,7 +240,7 @@ fprintln :: proc( wprint :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -251,7 +250,7 @@ wprint :: proc( wprintln :: proc( w: io.Writer, instructions: []Instruction, inst_info: []Instruction_Info, label_defs: []Label_Definition, - tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^map[u32]string = nil, + tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, label_names: ^isa.Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -344,11 +343,10 @@ write_register :: proc(sb: ^strings.Builder, r: Register, uppercase: bool, eleme @(private="file") write_operand :: proc( - sb: ^strings.Builder, - op: ^Operand, - offset_to_label: map[u32]u32, - label_names: ^map[u32]string, - opts: ^Print_Options, + sb: ^strings.Builder, + op: ^Operand, + display: ^isa.Label_Display, + opts: ^Print_Options, ) { switch op.kind { case .NONE: @@ -381,31 +379,14 @@ write_operand :: proc( case .RELATIVE: target := u32(op.relative) - if id, has := offset_to_label[target]; has { - write_label(sb, id, label_names, opts) + if isa.label_display_at(display, target) { + isa.label_display_write(display, sb, target, opts.label_prefix) } else { isa.print_hex(sb, u64(target), opts) } } } -@(private="file") -write_label :: proc( - sb: ^strings.Builder, - label_id: u32, - label_names: ^map[u32]string, - opts: ^Print_Options, -) { - if label_names != nil { - if name, has := label_names^[label_id]; has { - strings.write_string(sb, name) - return - } - } - strings.write_string(sb, opts.label_prefix) - write_decimal_u32(sb, label_id) -} - @(private="file") write_decimal_u32 :: proc(sb: ^strings.Builder, v: u32) { if v == 0 { diff --git a/core/rexcode/isa/x86/labels.odin b/core/rexcode/isa/x86/labels.odin index af31cdd8b..a40bc0b50 100644 --- a/core/rexcode/isa/x86/labels.odin +++ b/core/rexcode/isa/x86/labels.odin @@ -19,3 +19,5 @@ import "core:rexcode/isa" Label_Definition :: isa.Label_Definition Label_Map :: isa.Label_Map LABEL_UNDEFINED :: isa.LABEL_UNDEFINED +Label_Offset :: isa.Label_Offset +Label_Names :: isa.Label_Names diff --git a/core/rexcode/isa/x86/printer.odin b/core/rexcode/isa/x86/printer.odin index 42ef7a5bf..22d596a7d 100644 --- a/core/rexcode/isa/x86/printer.odin +++ b/core/rexcode/isa/x86/printer.odin @@ -282,7 +282,7 @@ sbprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, // Optional: for named label output (id → name) + label_names: ^Label_Names = nil, // Optional: for named label output (id → name) ) { options := options != nil ? options^ : DEFAULT_PRINT_OPTIONS @@ -300,30 +300,25 @@ sbprint :: proc( } } + // Display-side label naming: numbers in ADDRESS order (independent of the internal ids' + // allocation order), caller names keyed by byte offset (isa.Label_Display). + display: isa.Label_Display + isa.label_display_init(&display, label_defs, label_names) + defer isa.label_display_destroy(&display) + for &inst, instruction_index in instructions { info := &inst_info[instruction_index] - // Check if there's a label at this offset - for label_def, label_id in label_defs { - if label_def != LABEL_UNDEFINED && u32(label_def) == info.offset { - // Print label definition - start := strings.builder_len(sb^) - name: string; ok: bool - if label_names != nil { name, ok = label_names^[u32(label_id)] } - if ok { - strings.write_string(sb, name) - } else { - strings.write_string(sb, options.label_prefix) - print_decimal(sb, u32(label_id)) - } - strings.write_byte(sb, ':') - emit_token(tokens, sb, .LABEL_DEF, 0xFFFF, start) + // A displayable label at this offset — a definition, or a caller-named offset + if isa.label_display_at(&display, info.offset) { + start := strings.builder_len(sb^) + isa.label_display_write(&display, sb, info.offset, options.label_prefix) + strings.write_byte(sb, ':') + emit_token(tokens, sb, .LABEL_DEF, 0xFFFF, start) - start = strings.builder_len(sb^) - strings.write_string(sb, options.separator) - emit_token(tokens, sb, .NEWLINE, 0xFFFF, start) - break - } + start = strings.builder_len(sb^) + strings.write_string(sb, options.separator) + emit_token(tokens, sb, .NEWLINE, 0xFFFF, start) } // Print offset if requested, otherwise indent @@ -384,31 +379,13 @@ sbprint :: proc( write_memory_with_tokens(sb, op.mem, &options, tokens, u16(instruction_index)) case .RELATIVE: - // Compute absolute target and check if it matches a label + // Compute absolute target and name it if a displayable label sits there inst_end := i64(info.offset) + i64(inst.length) target := inst_end + op.relative - // Find label at this target - found_label: u32 = 0 - found_label_valid := false - for lbl_id in 0..= 0 && target <= i64(max(u32)) && isa.label_display_at(&display, u32(target)) { start := strings.builder_len(sb^) - name: string; ok: bool - if label_names != nil { name, ok = label_names^[found_label] } - if ok { - strings.write_string(sb, name) - } else { - strings.write_string(sb, options.label_prefix) - print_decimal(sb, found_label) - } + isa.label_display_write(&display, sb, u32(target), options.label_prefix) emit_token(tokens, sb, .LABEL_REF, u16(instruction_index), start) } else { start := strings.builder_len(sb^) @@ -558,7 +535,7 @@ sbprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { #force_inline sbprint(sb, instructions, inst_info, label_defs, tokens, options, label_names) strings.write_byte(sb, '\n') @@ -571,7 +548,7 @@ print :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) #force_inline sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -586,7 +563,7 @@ println :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) #force_inline sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -601,7 +578,7 @@ aprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -617,7 +594,7 @@ aprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, allocator := context.allocator, ) -> string { sb := strings.builder_make(allocator) @@ -633,7 +610,7 @@ tprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, allocator := context.temp_allocator, ) -> string { sb := strings.builder_make(allocator) @@ -649,7 +626,7 @@ tprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, allocator := context.temp_allocator, ) -> string { sb := strings.builder_make(allocator) @@ -666,7 +643,7 @@ bprint :: #force_inline proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) -> string { sb := strings.builder_from_slice(buf) #force_inline sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -682,7 +659,7 @@ bprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) -> string { sb := strings.builder_from_slice(buf) #force_inline sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -698,7 +675,7 @@ fprint :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) #force_inline sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -714,7 +691,7 @@ fprintln :: proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) #force_inline sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -730,7 +707,7 @@ wprint :: #force_inline proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprint(&sb, instructions, inst_info, label_defs, tokens, options, label_names) @@ -746,7 +723,7 @@ wprintln :: #force_inline proc( label_defs: []Label_Definition, tokens: ^[dynamic]Token = nil, options: ^Print_Options = nil, - label_names: ^map[u32]string = nil, + label_names: ^Label_Names = nil, ) { sb := strings.builder_make(context.temp_allocator) sbprintln(&sb, instructions, inst_info, label_defs, tokens, options, label_names) diff --git a/core/rexcode/isa/x86/tests/test.odin b/core/rexcode/isa/x86/tests/test.odin index 7a0be6d6b..6131459a0 100644 --- a/core/rexcode/isa/x86/tests/test.odin +++ b/core/rexcode/isa/x86/tests/test.odin @@ -3010,10 +3010,11 @@ run_label_map_tests :: proc() { x86.decode(code_buf[:byte_count], nil, &decoded_insts, &decoded_info, &decoded_labels, &decode_errors) - // Print with named labels (printer wants id→name; Label_Map stores name→id). - id_to_name := make(map[u32]string, len(lm.names), context.temp_allocator) - for name, id in lm.names { id_to_name[id] = name } - output := x86.tprint(decoded_insts[:], decoded_info[:], lm.labels[:], label_names=&id_to_name) + // Print with named labels (printer wants BYTE OFFSET → name; Label_Map stores name → id, and + // after encode each id's Label_Definition holds its byte offset). + names := make(x86.Label_Names, len(lm.names), context.temp_allocator) + for name, id in lm.names { names[x86.Label_Offset(u32(lm.labels[id]))] = name } + output := x86.tprint(decoded_insts[:], decoded_info[:], lm.labels[:], label_names=&names) // Verify output contains named labels // Note: JNZ and JNE are the same instruction, decoder may output either