kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 0f85365d6934d1507a8da340e71118dc91b8ce4a
parent 619a06df5b377adca4306a10108923d8cb3365ef
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 14 May 2026 12:20:19 -0700

Add internal arch registration descriptor

Diffstat:
Adoc/arch-registration-plan.md | 20++++++++++++++++++++
Msrc/api/arch_regs.c | 44++++++++++++++------------------------------
Asrc/arch/aarch64/arch.c | 23+++++++++++++++++++++++
Msrc/arch/arch.h | 20++++++++++++++++++++
Msrc/arch/cgtarget.c | 31+++++++++++--------------------
Msrc/arch/disasm.c | 25+++++++++----------------
Asrc/arch/registry.c | 23+++++++++++++++++++++++
Asrc/arch/rv64/arch.c | 16++++++++++++++++
Asrc/arch/x64/arch.c | 16++++++++++++++++
Msrc/link/link_arch.c | 16++++------------
10 files changed, 156 insertions(+), 78 deletions(-)

diff --git a/doc/arch-registration-plan.md b/doc/arch-registration-plan.md @@ -0,0 +1,20 @@ +# Architecture Registration Plan + +## Checklist + +- [x] Introduce one internal arch descriptor and registry lookup. +- [x] Route existing arch dispatchers through that descriptor without changing behavior. +- [ ] Move ABI selection behind the arch descriptor. +- [ ] Move object-format relocation translators behind the arch descriptor. +- [ ] Move linker-only arch constants and stub emitters fully behind the descriptor. +- [ ] Move assembler/disassembler/register helpers behind arch-owned implementation files. +- [ ] Make `MCEmitter` delegate label fixup encoding to the arch descriptor. +- [ ] Consolidate files into `src/arch/{aa64,rv64,x64}/` with one exposed implementation object per arch. +- [ ] Teach the build to honor `CFREE_ARCHS` and compile only selected arch subtrees. +- [ ] Add targeted subset-build tests for `aa64`, `x64`, `rv64`, and mixed subsets. + +## Phase 1 + +Phase 1 is a refactor-only step. It adds the shared descriptor boundary and +rewires existing centralized dispatchers to use it while all currently supported +architectures remain compiled in by default. diff --git a/src/api/arch_regs.c b/src/api/arch_regs.c @@ -1,49 +1,33 @@ -/* Public arch register name API. - * - * Stateless dispatch onto the per-arch register table. v1 wires aarch64 - * only; other arches return zero / unknown. */ +/* Public arch register name API. */ #include <cfree.h> - #include <stddef.h> -#include "arch/aa64_regs.h" +#include "arch/arch.h" const char* cfree_arch_register_name(CfreeArchKind arch, uint32_t dwarf_idx) { - switch (arch) { - case CFREE_ARCH_ARM_64: - return aa64_register_name(dwarf_idx); - default: - return NULL; - } + const ArchImpl* impl = arch_lookup(arch); + if (!impl || !impl->register_name) return NULL; + return impl->register_name(dwarf_idx); } int cfree_arch_register_index(CfreeArchKind arch, const char* name, uint32_t* idx_out) { - switch (arch) { - case CFREE_ARCH_ARM_64: - return aa64_register_index(name, idx_out); - default: - return 1; - } + const ArchImpl* impl = arch_lookup(arch); + if (!impl || !impl->register_index) return 1; + return impl->register_index(name, idx_out); } uint32_t cfree_arch_register_count(CfreeArchKind arch) { - switch (arch) { - case CFREE_ARCH_ARM_64: - return aa64_register_iter_size(); - default: - return 0; - } + const ArchImpl* impl = arch_lookup(arch); + if (!impl || !impl->register_count) return 0; + return impl->register_count(); } int cfree_arch_register_at(CfreeArchKind arch, uint32_t idx, CfreeArchReg* out) { if (!out) return 1; - switch (arch) { - case CFREE_ARCH_ARM_64: - return aa64_register_iter_get(idx, &out->dwarf_idx, &out->name); - default: - return 1; - } + const ArchImpl* impl = arch_lookup(arch); + if (!impl || !impl->register_at) return 1; + return impl->register_at(idx, out); } diff --git a/src/arch/aarch64/arch.c b/src/arch/aarch64/arch.c @@ -0,0 +1,23 @@ +#include "arch/arch.h" + +#include "arch/aa64.h" +#include "arch/aa64_disasm.h" +#include "arch/aa64_regs.h" +#include "link/link_arch.h" + +static int aa64_register_at_public(uint32_t idx, CfreeArchReg* out) { + if (!out) return 1; + return aa64_register_iter_get(idx, &out->dwarf_idx, &out->name); +} + +const ArchImpl arch_impl_aa64 = { + .kind = CFREE_ARCH_ARM_64, + .name = "aa64", + .cgtarget_new = aa64_cgtarget_new, + .disasm_new = aa64_disasm_new, + .link = &link_arch_aa64, + .register_name = aa64_register_name, + .register_index = aa64_register_index, + .register_count = aa64_register_iter_size, + .register_at = aa64_register_at_public, +}; diff --git a/src/arch/arch.h b/src/arch/arch.h @@ -700,6 +700,26 @@ struct ArchDisasm { void (*destroy)(ArchDisasm*); }; +typedef struct LinkArchDesc LinkArchDesc; + +typedef struct ArchImpl { + CfreeArchKind kind; + const char* name; + + CGTarget* (*cgtarget_new)(Compiler*, ObjBuilder*, MCEmitter*); + ArchDisasm* (*disasm_new)(Compiler*); + + const LinkArchDesc* link; + + const char* (*register_name)(uint32_t dwarf_idx); + int (*register_index)(const char* name, uint32_t* idx_out); + uint32_t (*register_count)(void); + int (*register_at)(uint32_t idx, CfreeArchReg* out); +} ArchImpl; + +const ArchImpl* arch_lookup(CfreeArchKind); +const ArchImpl* arch_for_compiler(const Compiler*); + ArchDisasm* arch_disasm_new(Compiler*); u32 arch_disasm_decode(ArchDisasm*, const u8* bytes, size_t len, u64 vaddr, CfreeInsn* out); diff --git a/src/arch/cgtarget.c b/src/arch/cgtarget.c @@ -1,28 +1,19 @@ -/* Public CGTarget constructor — dispatches by Compiler.target.arch. +/* Public CGTarget constructor — dispatches through the registered arch impl. * - * Per-arch constructors live in their own files (aa64.c, x64.c, rv64.c). - * The lifecycle helpers (cgtarget_finalize, cgtarget_free) are arch- - * agnostic shims over the vtable. */ + * The lifecycle helpers (cgtarget_finalize, cgtarget_free) are arch-agnostic + * shims over the vtable. */ -#include "arch/aa64.h" #include "arch/arch.h" -#include "arch/rv64.h" -#include "arch/x64.h" CGTarget* cgtarget_new(Compiler* c, ObjBuilder* o, MCEmitter* m) { - switch (c->target.arch) { - case CFREE_ARCH_ARM_64: - return aa64_cgtarget_new(c, o, m); - case CFREE_ARCH_X86_64: - return x64_cgtarget_new(c, o, m); - case CFREE_ARCH_RV64: - return rv64_cgtarget_new(c, o, m); - default: { - SrcLoc loc = {0, 0, 0}; - compiler_panic(c, loc, - "cgtarget_new: unsupported target arch %d", - (int)c->target.arch); - } + const ArchImpl* arch = arch_for_compiler(c); + if (arch && arch->cgtarget_new) { + return arch->cgtarget_new(c, o, m); + } + { + SrcLoc loc = {0, 0, 0}; + compiler_panic(c, loc, "cgtarget_new: unsupported target arch %d", + (int)c->target.arch); } } diff --git a/src/arch/disasm.c b/src/arch/disasm.c @@ -1,23 +1,16 @@ -/* Disassembler dispatcher — peer of src/arch/cgtarget.c. - * - * Per-arch ArchDisasm constructors live in their own files. v1 wires - * aarch64 only; x86_64 / rv64 panic with a clean diagnostic so a build - * that asks for those targets dies loudly instead of returning NULL - * silently. arch_disasm_decode / arch_disasm_free are vtable thunks. */ +/* Disassembler dispatcher — peer of src/arch/cgtarget.c. */ -#include "arch/aa64_disasm.h" #include "arch/arch.h" ArchDisasm* arch_disasm_new(Compiler* c) { - switch (c->target.arch) { - case CFREE_ARCH_ARM_64: - return aa64_disasm_new(c); - default: { - SrcLoc loc = {0, 0, 0}; - compiler_panic(c, loc, - "arch_disasm_new: unsupported target arch %d", - (int)c->target.arch); - } + const ArchImpl* arch = arch_for_compiler(c); + if (arch && arch->disasm_new) { + return arch->disasm_new(c); + } + { + SrcLoc loc = {0, 0, 0}; + compiler_panic(c, loc, "arch_disasm_new: unsupported target arch %d", + (int)c->target.arch); } } diff --git a/src/arch/registry.c b/src/arch/registry.c @@ -0,0 +1,23 @@ +#include "arch/arch.h" + +extern const ArchImpl arch_impl_aa64; +extern const ArchImpl arch_impl_rv64; +extern const ArchImpl arch_impl_x64; + +const ArchImpl* arch_lookup(CfreeArchKind arch) { + switch (arch) { + case CFREE_ARCH_ARM_64: + return &arch_impl_aa64; + case CFREE_ARCH_X86_64: + return &arch_impl_x64; + case CFREE_ARCH_RV64: + return &arch_impl_rv64; + default: + return NULL; + } +} + +const ArchImpl* arch_for_compiler(const Compiler* c) { + if (!c) return NULL; + return arch_lookup(c->target.arch); +} diff --git a/src/arch/rv64/arch.c b/src/arch/rv64/arch.c @@ -0,0 +1,16 @@ +#include "arch/arch.h" + +#include "arch/rv64.h" +#include "link/link_arch.h" + +const ArchImpl arch_impl_rv64 = { + .kind = CFREE_ARCH_RV64, + .name = "rv64", + .cgtarget_new = rv64_cgtarget_new, + .disasm_new = NULL, + .link = &link_arch_rv64, + .register_name = NULL, + .register_index = NULL, + .register_count = NULL, + .register_at = NULL, +}; diff --git a/src/arch/x64/arch.c b/src/arch/x64/arch.c @@ -0,0 +1,16 @@ +#include "arch/arch.h" + +#include "arch/x64.h" +#include "link/link_arch.h" + +const ArchImpl arch_impl_x64 = { + .kind = CFREE_ARCH_X86_64, + .name = "x64", + .cgtarget_new = x64_cgtarget_new, + .disasm_new = NULL, + .link = &link_arch_x64, + .register_name = NULL, + .register_index = NULL, + .register_count = NULL, + .register_at = NULL, +}; diff --git a/src/link/link_arch.c b/src/link/link_arch.c @@ -1,19 +1,11 @@ -/* Per-arch link descriptor dispatcher. See link_arch.h for the - * struct contract. Concrete descriptors live in link_arch_<arch>.c. */ +/* Per-arch link descriptor dispatcher. */ #include "link/link_arch.h" +#include "arch/arch.h" #include "core/core.h" const LinkArchDesc* link_arch_desc_for(const Compiler* c) { - switch (c->target.arch) { - case CFREE_ARCH_ARM_64: - return &link_arch_aa64; - case CFREE_ARCH_X86_64: - return &link_arch_x64; - case CFREE_ARCH_RV64: - return &link_arch_rv64; - default: - return NULL; - } + const ArchImpl* arch = arch_for_compiler(c); + return arch ? arch->link : NULL; }