kit

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

commit 0f62395863b90231877320b7f7c8f669f8023133
parent 71f06498a9a5b3f6eafdd71b49d3bed19615bc6a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 10 Jun 2026 07:01:25 -0700

cleanup: F.3 dwarf attr-skip dedup + G.4 RV disasm encoding dispatch

F.3: collapse the 6 pure-skip attr loops in dwarf_die.c onto the existing
dw_skip_die_attrs helper (read+skip two-pass sites in dwarf_open.c left
alone). No behavior change.

G.4: rv64_decode_flags now derives the CR-format control-flow flags from
the instruction encoding (rs2==0 && rd/rs1!=0 picks c.jr/c.jalr; bit[12]
picks the linking c.jalr) instead of strcmp on the mnemonic string. Adds
decode_compressed_cr_flags to rv64_decode_test pinning c.jr/c.jalr/c.mv/
c.add flags.

test-isa (rv64_decode 95 checks/0 fail), test-dwarf, test-debug, test-asm
all green.

Diffstat:
Mdoc/plan/TODO.md | 7-------
Msrc/arch/riscv/disasm.c | 15+++++++++++----
Msrc/debug/dwarf_die.c | 42++++++------------------------------------
Mtest/arch/rv64_decode_test.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 64 insertions(+), 47 deletions(-)

diff --git a/doc/plan/TODO.md b/doc/plan/TODO.md @@ -114,13 +114,6 @@ Add new deferred fixes below as they are discovered. (`cc_default_obj_path_for_name`, `cc_dep_default_target`, `build_default_obj_name`); its home is the driver util layer (`driver/`), not `link_inputs.c`. (The link pipeline + flag-parse blocks were assessed and are not byte-identical — different option structs.) -- **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`.) -- **G.4 — RV disassembler dispatches sub-format by `strcmp`** on the mnemonic display - string (`src/arch/riscv/disasm.c`) rather than an encoding tag. - **I.1 — C parser shadow stack** is a 3-array struct-of-arrays (`lang/c/parse/cg_adapter.c:53-141`) whose dup/swap/rot3/grow shuffle 3 lanes in lockstep; collapse into one `PcgSlot{type;flags;aux;}` array. (Touches the parser↔CG diff --git a/src/arch/riscv/disasm.c b/src/arch/riscv/disasm.c @@ -177,13 +177,20 @@ static u16 rv64_decode_flags(const Rv64InsnDesc* desc, u32 word) { if (rd == RV_ZERO && rs1 == RV_RA) flags |= KIT_DECODE_RET; break; } - case RV64_FMT_CR: - if (slice_eq_cstr(desc->mnemonic, "c.jr") || - slice_eq_cstr(desc->mnemonic, "c.jalr")) { + case RV64_FMT_CR: { + /* CR holds c.jr/c.jalr (rs2==0, rd/rs1!=0) and c.mv/c.add (rs2!=0). + * Dispatch on the encoding rather than the mnemonic string: only the + * jr/jalr pair is a control transfer, and bit[12] selects c.jalr (which + * links ra, so it is a call). */ + u32 hw = word & 0xffffu; + u32 rs2 = (hw >> 2) & 0x1fu; /* bits[6:2] */ + u32 rd_rs1 = (hw >> 7) & 0x1fu; /* bits[11:7] */ + if (rs2 == 0u && rd_rs1 != 0u) { flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH; - if (slice_eq_cstr(desc->mnemonic, "c.jalr")) flags |= KIT_DECODE_CALL; + if (((hw >> 12) & 1u) != 0u) flags |= KIT_DECODE_CALL; /* c.jalr */ } break; + } case RV64_FMT_SYSTEM: if (word == rv_ecall() || word == rv_ebreak()) flags |= KIT_DECODE_TERMINATOR | KIT_DECODE_TRAP; diff --git a/src/debug/dwarf_die.c b/src/debug/dwarf_die.c @@ -189,18 +189,10 @@ static void walk_for_subs(KitDebugInfo* d, u32 cu_idx, u32* off) { } } else if (die.abbrev->has_children) { /* Skip attrs, then descend. */ - u32 i; - for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; - dw_skip_form(d, cu, aa->form, aa->implicit_const, off); - } + dw_skip_die_attrs(d, cu, &die, off); walk_for_subs(d, cu_idx, off); } else { - u32 i; - for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; - dw_skip_form(d, cu, aa->form, aa->implicit_const, off); - } + dw_skip_die_attrs(d, cu, &die, off); } } } @@ -216,13 +208,7 @@ void dw_build_subs(KitDebugInfo* d) { DwDie root; if (!dw_read_die(d, cu, &off, &root)) continue; /* Skip root attrs */ - { - u32 j; - for (j = 0; j < root.abbrev->nattrs; ++j) { - DwAbbrevAttr* aa = &root.abbrev->attrs[j]; - dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); - } - } + dw_skip_die_attrs(d, cu, &root, &off); if (root.abbrev->has_children) walk_for_subs(d, i, &off); } } @@ -320,11 +306,7 @@ static void walk_subprog_body(LocalCtx* x, u32* off, u64 scope_lo, u64 scope_hi, walk_subprog_body(x, off, lo, hi, die.die_off, 1); } } else { - u32 i; - for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; - dw_skip_form(d, cu, aa->form, aa->implicit_const, off); - } + dw_skip_die_attrs(d, cu, &die, off); if (die.abbrev->has_children) walk_subprog_body(x, off, scope_lo, scope_hi, scope_die_off, has_scope); } @@ -343,13 +325,7 @@ void dw_build_locals(KitDebugInfo* d, DwSubprog* sp) { if (!dw_read_die(d, cu, &off, &die)) return; if (!die.abbrev || !die.abbrev->has_children) return; /* Skip subprog attrs */ - { - u32 i; - for (i = 0; i < die.abbrev->nattrs; ++i) { - DwAbbrevAttr* aa = &die.abbrev->attrs[i]; - dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); - } - } + dw_skip_die_attrs(d, cu, &die, &off); memset(&x, 0, sizeof(x)); x.d = d; x.cu_idx = sp->cu_idx; @@ -371,13 +347,7 @@ void dw_build_globals(KitDebugInfo* d) { u32 off = cu->die_start_off; DwDie root; if (!dw_read_die(d, cu, &off, &root)) continue; - { - u32 j; - for (j = 0; j < root.abbrev->nattrs; ++j) { - DwAbbrevAttr* aa = &root.abbrev->attrs[j]; - dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); - } - } + dw_skip_die_attrs(d, cu, &root, &off); if (!root.abbrev->has_children) continue; /* Walk only top-level children of the CU; collect DW_TAG_variable. */ for (;;) { diff --git a/test/arch/rv64_decode_test.c b/test/arch/rv64_decode_test.c @@ -37,6 +37,11 @@ static void put32(unsigned char* b, size_t off, unsigned v) { b[off + 3] = (unsigned char)(v >> 24); } +static void put16(unsigned char* b, size_t off, unsigned v) { + b[off + 0] = (unsigned char)v; + b[off + 1] = (unsigned char)(v >> 8); +} + static void decode_addi(KitCompiler* pub) { Compiler* c = (Compiler*)pub; unsigned char bytes[4]; @@ -171,6 +176,47 @@ static void csr_pseudos_match_full_form(KitCompiler* pub) { } } +/* The CR compressed format packs c.jr/c.jalr (rs2==0, rd/rs1!=0) and + * c.mv/c.add (rs2!=0). rv64_decode_flags derives the control-flow flags from + * the encoding (bit[12] picks the linking c.jalr) rather than the mnemonic + * string; pin that decode here so the dispatch stays encoding-driven. */ +static unsigned cr_word(unsigned bit12, unsigned rd_rs1, unsigned rs2) { + return (4u << 13) | ((bit12 & 1u) << 12) | ((rd_rs1 & 0x1fu) << 7) | + ((rs2 & 0x1fu) << 2) | 2u; +} + +static void expect_cr_flags(KitCompiler* pub, unsigned word, u16 want_set, + u16 want_clear, const char* what) { + Compiler* c = (Compiler*)pub; + unsigned char bytes[4]; + KitDecodedInsn insn; + KitStatus st; + memset(bytes, 0, sizeof(bytes)); + put16(bytes, 0, word); + memset(&insn, 0, sizeof(insn)); + st = arch_decode_one(c, bytes, sizeof(bytes), 0x7000, &insn); + EXPECT(st == KIT_OK, "decode_one(%s) status %d", what, (int)st); + EXPECT(insn.nbytes == 2, "%s nbytes = %u (want 2)", what, + (unsigned)insn.nbytes); + EXPECT((insn.flags & want_set) == want_set, + "%s flags 0x%x missing 0x%x", what, (unsigned)insn.flags, + (unsigned)want_set); + EXPECT((insn.flags & want_clear) == 0, "%s flags 0x%x should clear 0x%x", + what, (unsigned)insn.flags, (unsigned)want_clear); +} + +static void decode_compressed_cr_flags(KitCompiler* pub) { + u16 br = (u16)(KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH); + u16 ctrl = (u16)(KIT_DECODE_TERMINATOR | KIT_DECODE_BRANCH | KIT_DECODE_CALL); + /* c.jr ra: branch terminator, not a call. */ + expect_cr_flags(pub, cr_word(0, RV_RA, 0), br, (u16)KIT_DECODE_CALL, "c.jr"); + /* c.jalr ra: linking branch -> call. */ + expect_cr_flags(pub, cr_word(1, RV_RA, 0), ctrl, 0, "c.jalr"); + /* c.mv / c.add (rs2!=0): not control transfers. */ + expect_cr_flags(pub, cr_word(0, RV_A0, RV_A1), 0, ctrl, "c.mv"); + expect_cr_flags(pub, cr_word(1, RV_A0, RV_A1), 0, ctrl, "c.add"); +} + int main(void) { KitCompiler* c; kit_unit_init(&g_u); @@ -179,6 +225,7 @@ int main(void) { decode_block_stops_at_ecall(c); format_decoded_record(c); csr_pseudos_match_full_form(c); + decode_compressed_cr_flags(c); kit_compiler_free(c); kit_unit_summary(&g_u, "rv64_decode_test"); return kit_unit_status(&g_u);