mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-17 21:21:04 +00:00
rexcode/x86: generate the encode-recipe table (drop the @init interim)
Move ENCODE_RECIPES from a startup-built (@init) static table in the library to
a generated, #loaded table like every other one. The tablegen runs
form_to_recipe over every form, serializes to x86.encode_recipes.bin, and the
loader #loads it -- no @init, no allocation; the forms remain the single source
of truth and the recipe is derived from them.
- tablegen/gen.odin: ENCODE_RECIPES added to the BLOBS manifest (which drives
both the Stage B serializer and the loader's #load); emit the generated-package
global plus an @init that fills it from ENCODE_FORMS via lib.form_to_recipe.
- encoder_recipe.odin: drop the @init, the static storage, and the ENCODE_RECIPES
declaration. form_to_recipe stays -- now solely the tablegen-time derivation.
- tables.odin, generated/{encode_tables,writer}.odin: regenerated.
- tables/x86.encode_recipes.bin: the generated blob (28260 bytes = 2355 x 12).
No behavior change: the recipes are identical to the @init ones. gen / builders /
check / test / idempotent green (2282 cases, 22 byte-stable artifacts); encode
perf unchanged.
This commit is contained in:
@@ -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..<n {
|
||||
encode_recipes_storage[i] = form_to_recipe(&ENCODE_FORMS[i])
|
||||
}
|
||||
ENCODE_RECIPES = encode_recipes_storage[:n]
|
||||
}
|
||||
// ENCODE_RECIPES (parallel to ENCODE_FORMS) is generated, not built here: the
|
||||
// tablegen runs form_to_recipe over every form, serializes the result to
|
||||
// x86.encode_recipes.bin, and tables.odin #loads it. So form_to_recipe above is
|
||||
// a tablegen-time helper -- it is not called on the encode hot path.
|
||||
|
||||
@(private)
|
||||
op_is_spl :: #force_inline proc "contextless" (op: ^Operand) -> bool {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
core/rexcode/isa/x86/tables/x86.encode_recipes.bin
Normal file
BIN
core/rexcode/isa/x86/tables/x86.encode_recipes.bin
Normal file
Binary file not shown.
Reference in New Issue
Block a user