diff --git a/core/rexcode/isa/x86/encoder_recipe.odin b/core/rexcode/isa/x86/encoder_recipe.odin index 350bc39ed..b63878606 100644 --- a/core/rexcode/isa/x86/encoder_recipe.odin +++ b/core/rexcode/isa/x86/encoder_recipe.odin @@ -18,10 +18,9 @@ package rexcode_x86 // marked `eligible = false` and falls back to the existing interpreter, which // stays the source of truth for correctness. // -// NOTE(interim): ENCODE_RECIPES is currently built at startup from the #loaded -// ENCODE_FORMS (static storage, no heap). Once the fast path is validated this -// moves into the table generator -- serialized and #loaded like every other -// table, with no @init. +// ENCODE_RECIPES is produced by the tablegen (form_to_recipe over every form) +// and #loaded from x86.encode_recipes.bin like every other table -- see the note +// by form_to_recipe below. Form_Recipe :: struct { prefix: u8, // mandatory legacy prefix emitted before REX (0 = none) @@ -121,23 +120,10 @@ form_to_recipe :: proc "contextless" (enc: ^Encoding) -> (r: Form_Recipe) { return } -// ----------------------------------------------------------------------------- -// Interim recipe table: built once at startup from the #loaded forms into static -// storage (no heap). ENCODE_RECIPES is parallel to ENCODE_FORMS. -// ----------------------------------------------------------------------------- - -@(private) ENCODE_RECIPE_CAP :: 4096 -@(private) encode_recipes_storage: [ENCODE_RECIPE_CAP]Form_Recipe -ENCODE_RECIPES: []Form_Recipe - -@(init) -build_encode_recipes :: proc "contextless" () { - n := min(len(ENCODE_FORMS), ENCODE_RECIPE_CAP) - for i in 0.. bool { diff --git a/core/rexcode/isa/x86/tablegen/gen.odin b/core/rexcode/isa/x86/tablegen/gen.odin index 0a9ccc038..65f38a3ea 100644 --- a/core/rexcode/isa/x86/tablegen/gen.odin +++ b/core/rexcode/isa/x86/tablegen/gen.odin @@ -44,8 +44,9 @@ Blob :: struct { global, file, typ: string } @(rodata) BLOBS := [?]Blob{ - {"ENCODE_FORMS", "x86.encode_forms.bin", "Encoding"}, - {"ENCODE_RUNS", "x86.encode_runs.bin", "Encode_Run"}, + {"ENCODE_FORMS", "x86.encode_forms.bin", "Encoding"}, + {"ENCODE_RUNS", "x86.encode_runs.bin", "Encode_Run"}, + {"ENCODE_RECIPES", "x86.encode_recipes.bin", "Form_Recipe"}, {"MODRM_TABLE", "x86.modrm.bin", "ModRM_Info"}, {"SIB_TABLE", "x86.sib.bin", "SIB_Info"}, {"LEGACY_DECODE_ENTRIES", "x86.legacy.bin", "Decode_Entry"}, @@ -123,6 +124,18 @@ emit_encode_tables :: proc() { start += n } strings.write_string(&sb, "}\n") + + // Emit descriptor per form: the flattened recipe the encoder replays, derived + // from the forms via the library's form_to_recipe (single source of truth). + // Filled here at startup and serialized to x86.encode_recipes.bin; the loader + // #loads it, so the library itself needs no @init. + strings.write_string(&sb, "\n// Emit descriptor per form (derived from ENCODE_FORMS via lib.form_to_recipe).\n") + fmt.sbprintfln(&sb, "ENCODE_RECIPES: [%d]lib.Form_Recipe", total_forms()) + strings.write_string(&sb, "@(init) _fill_recipes :: proc \"contextless\" () {\n") + strings.write_string(&sb, "\tfor i in 0 ..< len(ENCODE_FORMS) {\n") + strings.write_string(&sb, "\t\tENCODE_RECIPES[i] = lib.form_to_recipe(&ENCODE_FORMS[i])\n") + strings.write_string(&sb, "\t}\n}\n") + emit_file(DIR_GEN + "encode_tables.odin", &sb) } diff --git a/core/rexcode/isa/x86/tablegen/generated/encode_tables.odin b/core/rexcode/isa/x86/tablegen/generated/encode_tables.odin index 11d45ce67..c743f7d0a 100644 --- a/core/rexcode/isa/x86/tablegen/generated/encode_tables.odin +++ b/core/rexcode/isa/x86/tablegen/generated/encode_tables.odin @@ -4720,3 +4720,11 @@ ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{ .RDRAND = { 2349, 3}, .RDSEED = { 2352, 3}, } + +// Emit descriptor per form (derived from ENCODE_FORMS via lib.form_to_recipe). +ENCODE_RECIPES: [2355]lib.Form_Recipe +@(init) _fill_recipes :: proc "contextless" () { + for i in 0 ..< len(ENCODE_FORMS) { + ENCODE_RECIPES[i] = lib.form_to_recipe(&ENCODE_FORMS[i]) + } +} diff --git a/core/rexcode/isa/x86/tablegen/generated/writer.odin b/core/rexcode/isa/x86/tablegen/generated/writer.odin index fec97ef84..7a91efc83 100644 --- a/core/rexcode/isa/x86/tablegen/generated/writer.odin +++ b/core/rexcode/isa/x86/tablegen/generated/writer.odin @@ -24,6 +24,7 @@ w :: proc(file: string, data: []u8) { main :: proc() { w(TABLES + "x86.encode_forms.bin", raw(&ENCODE_FORMS, size_of(ENCODE_FORMS))) w(TABLES + "x86.encode_runs.bin", raw(&ENCODE_RUNS, size_of(ENCODE_RUNS))) + w(TABLES + "x86.encode_recipes.bin", raw(&ENCODE_RECIPES, size_of(ENCODE_RECIPES))) w(TABLES + "x86.modrm.bin", raw(&MODRM_TABLE, size_of(MODRM_TABLE))) w(TABLES + "x86.sib.bin", raw(&SIB_TABLE, size_of(SIB_TABLE))) w(TABLES + "x86.legacy.bin", raw(&LEGACY_DECODE_ENTRIES, size_of(LEGACY_DECODE_ENTRIES))) diff --git a/core/rexcode/isa/x86/tables.odin b/core/rexcode/isa/x86/tables.odin index 06aae9829..32a5c7af1 100644 --- a/core/rexcode/isa/x86/tables.odin +++ b/core/rexcode/isa/x86/tables.odin @@ -76,23 +76,24 @@ Decode_Index :: struct { // Loaded tables (rodata, embedded from tables/*.bin at compile time) // ----------------------------------------------------------------------------- -@(rodata) ENCODE_FORMS := #load("tables/x86.encode_forms.bin", []Encoding) -@(rodata) ENCODE_RUNS := #load("tables/x86.encode_runs.bin", []Encode_Run) -@(rodata) MODRM_TABLE := #load("tables/x86.modrm.bin", []ModRM_Info) -@(rodata) SIB_TABLE := #load("tables/x86.sib.bin", []SIB_Info) -@(rodata) LEGACY_DECODE_ENTRIES := #load("tables/x86.legacy.bin", []Decode_Entry) -@(rodata) VEX_DECODE_ENTRIES := #load("tables/x86.vex.bin", []VEX_Decode_Entry) -@(rodata) EVEX_DECODE_ENTRIES := #load("tables/x86.evex.bin", []VEX_Decode_Entry) -@(rodata) DECODE_INDEX_LEGACY := #load("tables/x86.idx_legacy.bin", []Decode_Index) -@(rodata) DECODE_INDEX_ESC_0F := #load("tables/x86.idx_0f.bin", []Decode_Index) -@(rodata) DECODE_INDEX_ESC_0F38 := #load("tables/x86.idx_0f38.bin", []Decode_Index) -@(rodata) DECODE_INDEX_ESC_0F3A := #load("tables/x86.idx_0f3a.bin", []Decode_Index) -@(rodata) VEX_INDEX_0F := #load("tables/x86.vex_idx_0f.bin", []Decode_Index) -@(rodata) VEX_INDEX_0F38 := #load("tables/x86.vex_idx_0f38.bin", []Decode_Index) -@(rodata) VEX_INDEX_0F3A := #load("tables/x86.vex_idx_0f3a.bin", []Decode_Index) -@(rodata) EVEX_INDEX_0F := #load("tables/x86.evex_idx_0f.bin", []Decode_Index) -@(rodata) EVEX_INDEX_0F38 := #load("tables/x86.evex_idx_0f38.bin", []Decode_Index) -@(rodata) EVEX_INDEX_0F3A := #load("tables/x86.evex_idx_0f3a.bin", []Decode_Index) +@(rodata) ENCODE_FORMS := #load("tables/x86.encode_forms.bin", []Encoding) +@(rodata) ENCODE_RUNS := #load("tables/x86.encode_runs.bin", []Encode_Run) +@(rodata) ENCODE_RECIPES := #load("tables/x86.encode_recipes.bin", []Form_Recipe) +@(rodata) MODRM_TABLE := #load("tables/x86.modrm.bin", []ModRM_Info) +@(rodata) SIB_TABLE := #load("tables/x86.sib.bin", []SIB_Info) +@(rodata) LEGACY_DECODE_ENTRIES := #load("tables/x86.legacy.bin", []Decode_Entry) +@(rodata) VEX_DECODE_ENTRIES := #load("tables/x86.vex.bin", []VEX_Decode_Entry) +@(rodata) EVEX_DECODE_ENTRIES := #load("tables/x86.evex.bin", []VEX_Decode_Entry) +@(rodata) DECODE_INDEX_LEGACY := #load("tables/x86.idx_legacy.bin", []Decode_Index) +@(rodata) DECODE_INDEX_ESC_0F := #load("tables/x86.idx_0f.bin", []Decode_Index) +@(rodata) DECODE_INDEX_ESC_0F38 := #load("tables/x86.idx_0f38.bin", []Decode_Index) +@(rodata) DECODE_INDEX_ESC_0F3A := #load("tables/x86.idx_0f3a.bin", []Decode_Index) +@(rodata) VEX_INDEX_0F := #load("tables/x86.vex_idx_0f.bin", []Decode_Index) +@(rodata) VEX_INDEX_0F38 := #load("tables/x86.vex_idx_0f38.bin", []Decode_Index) +@(rodata) VEX_INDEX_0F3A := #load("tables/x86.vex_idx_0f3a.bin", []Decode_Index) +@(rodata) EVEX_INDEX_0F := #load("tables/x86.evex_idx_0f.bin", []Decode_Index) +@(rodata) EVEX_INDEX_0F38 := #load("tables/x86.evex_idx_0f38.bin", []Decode_Index) +@(rodata) EVEX_INDEX_0F3A := #load("tables/x86.evex_idx_0f3a.bin", []Decode_Index) // ----------------------------------------------------------------------------- // Accessors diff --git a/core/rexcode/isa/x86/tables/x86.encode_recipes.bin b/core/rexcode/isa/x86/tables/x86.encode_recipes.bin new file mode 100644 index 000000000..630a3239d Binary files /dev/null and b/core/rexcode/isa/x86/tables/x86.encode_recipes.bin differ