Extend the tablegen to emit encoding_table.odin from the grammar -- the
per-opcode operand layout that drives the codec:
INSTRUCTION_SPECS flat []Operand_Spec {Spec_Kind, Quantifier}
INSTRUCTION_INDEX [max_opcode+1]Spec_Run -- O(1) opcode -> its operand run
ENUM_PARAMS enumerant -> trailing-parameter operands, so the codec
PARAM_SPECS reads MemoryAccess.Aligned / OpExecutionMode LocalSize /
Decoration.SpecId etc. correctly
873 opcodes, 3693 operand specs. Package compiles.
Start the SPIR-V intermediate representation under core/rexcode/ir/spirv,
following the ir API (docs/ir_design.md) and the ISA package conventions. SPIR-V
is table-driven on encoding and SSA on dataflow, so it re-exports the shared ir
vocabulary and is laid out like an arch package.
spirv.odin package + ir re-exports + physical format (MAGIC, version,
Header, wordCount<<16|opcode framing)
module.odin Module :: struct { using base: ir.Module, ...sections... } --
capabilities, ext-imports, entry points, exec modes, constant
pool, decorations, debug; SPIR-V's module metadata has no
ir.Module slot, so it is carried alongside the core
reloc.odin Relocation (linkage import/export)
opcodes.odin GENERATED: the Opcode enum (873 opcodes)
operand_kinds.odin GENERATED: ValueEnum/BitEnum operand kinds + Spec_Kind
tablegen/gen.odin the generator (core:encoding/json)
tablegen/spirv.core.grammar.json vendored authoritative grammar (Khronos
SPIRV-Headers unified1) -- single source of truth
Generating from the authoritative grammar avoids hand-transcription errors
(hand-authoring had Quads/Aliased/... wrong). Package compiles. Codec
(encode/decode + flat<->structured lowering), printer, and tests are next.
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.
* For `-o:size` and below, uses the type erased approach
* For `-o:speed` and above, the inlined form is used
This is necessary because a generic `mem_copy_non_overlapping` cannot be optimized when type erasure is used, meaning in a hot path where `append_elem` is used a lot; thus `mem_copy_non_overlapping` becomes a bottleneck.