kit

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

commit 30d33c176ededa9a33f7bcd0e8c13473ff10ff46
parent cb415ed9fc863e0bb9281b4aa2526d8ef01e4cb0
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 10 Jun 2026 06:00:01 -0700

cleanup wave: dedups (B.5 register_at, F.4 dist path-join, F.3 LEB128)

B.5: collapse the three near-identical *_register_at_public wrappers (x64/aa64/
rv64 arch.c) onto a shared arch_register_at_public(idx, out, iter_get) inline in
src/arch/arch.h; each arch's register_at is now a one-line delegation.

F.4: drop the duplicate join_tree_path in src/dist/cas.c; its one caller
(dist_cas_materialize_tree) now uses the identical dist_cas_join_path.

F.3 (LEB128 half): extract form_uleb_inline / form_sleb_inline (raw-buffer
LEB128, byte-identical to the Buf* form_uleb/form_sleb) into debug_form.c and
use them for the DWARF exprloc DW_OP_regx / DW_OP_fbreg operands in debug_emit.c,
replacing two hand-rolled encode loops. (The dwarf-reader attr-skip consolidation
stays on the backlog.)

Verified: test-debug, test-dwarf, test-dist, test-cg-api, test-toy (1394/0/33).

Diffstat:
Mdoc/plan/TODO.md | 8+++++---
Msrc/arch/aa64/arch.c | 7+------
Msrc/arch/arch.h | 15+++++++++++++++
Msrc/arch/riscv/arch.c | 7+------
Msrc/arch/x64/arch.c | 7+------
Msrc/debug/debug_emit.c | 23+++--------------------
Msrc/debug/debug_form.c | 31+++++++++++++++++++++++++++++++
Msrc/debug/debug_internal.h | 2++
Msrc/dist/cas.c | 17+----------------
9 files changed, 60 insertions(+), 57 deletions(-)

diff --git a/doc/plan/TODO.md b/doc/plan/TODO.md @@ -127,9 +127,11 @@ Add new deferred fixes below as they are discovered. flag-parse blocks were assessed and are not byte-identical — different option structs.) - **F.2 — ELF strtab builder.** `objbb_append_str`'s dedup strtab builder is reimplemented as `StrBuilder`/`strtab_add` ~4× in `src/obj/elf/link.c`. Use the shared builder. -- **F.3 — LEB128 + dwarf attr-skip.** LEB128 encoders are forked in `src/debug/debug_emit.c`; - the `dw_skip_die_attrs` loop is inlined ~6× in the dwarf reader. One encoder + one skip - helper. +- **F.3 — dwarf attr-skip.** The `dw_skip_die_attrs` loop is inlined ~6× in the dwarf + reader (`src/debug/dwarf_open.c` / `dwarf_die.c`); collapse the pure-skip sites onto + the existing helper (leave the read+skip two-pass sites alone). (The LEB128 fork is + done: `form_uleb_inline`/`form_sleb_inline` in `debug_form.c` now back the exprloc + builder in `debug_emit.c`.) - **F.4 — path-join triplicated** (2 copies in one `src/dist/` file). (The `ctx->diag` varargs wrapper part of this finding is done — now `kit_ctx_diagf` in `core/diag`.) - **G.4 — RV disassembler dispatches sub-format by `strcmp`** on the mnemonic display diff --git a/src/arch/aa64/arch.c b/src/arch/aa64/arch.c @@ -18,12 +18,7 @@ extern const ArchDwarfOps aa64_dwarf_ops; extern const ArchAsmOps aa64_asm_ops; static int aa64_register_at_public(uint32_t idx, KitArchReg* out) { - const char* nm = NULL; - int rc; - if (!out) return 1; - rc = aa64_register_iter_get(idx, &out->dwarf_idx, &nm); - if (rc == 0) out->name = kit_slice_cstr(nm); - return rc; + return arch_register_at_public(idx, out, aa64_register_iter_get); } static void aa64_wr_u64_target(Compiler* c, u8* p, u64 v) { diff --git a/src/arch/arch.h b/src/arch/arch.h @@ -11,6 +11,21 @@ #include "core/core.h" #include "obj/obj.h" +/* Generic ArchImpl.register_at body: adapt a per-arch register_iter_get (which + * yields a DWARF index + a C-string name) into the public KitArchReg out + * struct. Each arch's register_at is a one-line wrapper delegating here with + * its own iter_get, so the conversion lives in exactly one place. */ +static inline int arch_register_at_public( + uint32_t idx, KitArchReg* out, + int (*iter_get)(uint32_t, uint32_t*, const char**)) { + const char* nm = NULL; + int rc; + if (!out) return 1; + rc = iter_get(idx, &out->dwarf_idx, &nm); + if (rc == 0) out->name = kit_slice_cstr(nm); + return rc; +} + typedef struct AsmDriver AsmDriver; typedef struct ArchAsm ArchAsm; diff --git a/src/arch/riscv/arch.c b/src/arch/riscv/arch.c @@ -22,12 +22,7 @@ extern const LinkArchDesc link_arch_rv32; extern const ArchDbgOps rv32_dbg_ops; static int rv64_register_at_public(uint32_t idx, KitArchReg* out) { - const char* nm = NULL; - int rc; - if (!out) return 1; - rc = rv64_register_iter_get(idx, &out->dwarf_idx, &nm); - if (rc == 0) out->name = kit_slice_cstr(nm); - return rc; + return arch_register_at_public(idx, out, rv64_register_iter_get); } static SrcLoc rv64_no_loc(void) { diff --git a/src/arch/x64/arch.c b/src/arch/x64/arch.c @@ -102,12 +102,7 @@ static void x64_target_feature_defaults(const Target* target, u64* words, } static int x64_register_at_public(uint32_t idx, KitArchReg* out) { - const char* nm = NULL; - int rc; - if (!out) return 1; - rc = x64_register_iter_get(idx, &out->dwarf_idx, &nm); - if (rc == 0) out->name = kit_slice_cstr(nm); - return rc; + return arch_register_at_public(idx, out, x64_register_iter_get); } static CgTarget* x64_backend_make(Compiler* c, ObjBuilder* o, diff --git a/src/debug/debug_emit.c b/src/debug/debug_emit.c @@ -534,31 +534,14 @@ static void emit_var_loc_exprloc(EmitCtx* e, Buf* b, DebugVarLoc loc) { if (loc.v.reg < 32) { expr[n++] = (u8)(DW_OP_reg0 + loc.v.reg); } else { - u64 v = loc.v.reg; expr[n++] = DW_OP_regx; - while (v >= 0x80) { - expr[n++] = (u8)((v & 0x7f) | 0x80); - v >>= 7; - } - expr[n++] = (u8)v; + n += form_uleb_inline(&expr[n], loc.v.reg); } break; - case DVL_FRAME: { - i64 v = loc.v.frame_ofs; - int more = 1; + case DVL_FRAME: expr[n++] = DW_OP_fbreg; - while (more) { - u8 byte = (u8)(v & 0x7f); - v >>= 7; - if ((v == 0 && (byte & 0x40) == 0) || (v == -1 && (byte & 0x40) != 0)) { - more = 0; - } else { - byte |= 0x80; - } - expr[n++] = byte; - } + n += form_sleb_inline(&expr[n], loc.v.frame_ofs); break; - } case DVL_GLOBAL: { /* DW_OP_addr <ptr_size>: relocation against the symbol. We can't * place a section reloc inside an exprloc body without computing diff --git a/src/debug/debug_form.c b/src/debug/debug_form.c @@ -83,3 +83,34 @@ size_t form_sleb_size(i64 v) { } return n; } + +/* LEB128 encoders into a raw fixed-size buffer (vs the Buf* form_uleb/form_sleb), + * for expression-byte builders that stage into a stack array. Caller guarantees + * room (<=10 bytes for u64, <=10 for i64). Returns the number of bytes written. */ +u32 form_uleb_inline(u8* buf, u64 v) { + u32 n = 0; + for (;;) { + u8 byte = (u8)(v & 0x7f); + v >>= 7; + if (v == 0) { + buf[n++] = byte; + return n; + } + buf[n++] = (u8)(byte | 0x80); + } +} + +u32 form_sleb_inline(u8* buf, i64 v) { + u32 n = 0; + int more = 1; + while (more) { + u8 byte = (u8)(v & 0x7f); + v >>= 7; /* arithmetic shift */ + if ((v == 0 && (byte & 0x40) == 0) || (v == -1 && (byte & 0x40) != 0)) + more = 0; + else + byte |= 0x80; + buf[n++] = byte; + } + return n; +} diff --git a/src/debug/debug_internal.h b/src/debug/debug_internal.h @@ -232,6 +232,8 @@ void form_uleb(Buf*, u64); void form_sleb(Buf*, i64); size_t form_uleb_size(u64); size_t form_sleb_size(i64); +u32 form_uleb_inline(u8* buf, u64 v); +u32 form_sleb_inline(u8* buf, i64 v); /* Abbrev pool ops (debug_abbrev.c). Teardown is abbrev_fini_heap (declared * in debug_abbrev.c) — it needs the heap to free the per-abbrev attr arrays. */ diff --git a/src/dist/cas.c b/src/dist/cas.c @@ -190,21 +190,6 @@ int dist_cas_get_tree(DistCas* cas, const uint8_t tree[DIST_BLAKE2B_LEN], return DIST_ERR; } -static int join_tree_path(char* out, size_t cap, const char* dst, - const char* rel) { - size_t dl, rl; - int needs_slash; - if (!out || !cap || !dst || !rel) return DIST_ERR; - dl = strlen(dst); - rl = strlen(rel); - needs_slash = dl > 0 && dst[dl - 1u] != '/'; - if (dl + (needs_slash ? 1u : 0u) + rl + 1u > cap) return DIST_ERR; - memcpy(out, dst, dl); - if (needs_slash) out[dl++] = '/'; - memcpy(out + dl, rel, rl); - out[dl + rl] = '\0'; - return DIST_OK; -} int dist_cas_materialize_tree(DistCas* cas, const DistTree* tree, const char* dst) { @@ -232,7 +217,7 @@ int dist_cas_materialize_tree(DistCas* cas, const DistTree* tree, goto entry_out; if (bi.size != e->size || memcmp(bi.root, e->root, DIST_BLAKE2B_LEN) != 0) goto entry_out; - if (join_tree_path(outpath, sizeof outpath, dst, e->path) != DIST_OK) + if (dist_cas_join_path(outpath, sizeof outpath, dst, e->path) != DIST_OK) goto entry_out; if (parent_dir(parent, sizeof parent, outpath) != DIST_OK) goto entry_out; if (cas->host.mkdir_p && cas->host.mkdir_p(cas->host.user, parent) != 0)