kit

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

commit 13beba6de38f1389ec3217e78f27ddacfabb57bc
parent db75a878a607b07c93cb48829fec994292984aa5
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 10 Jun 2026 08:23:02 -0700

cleanup: I.1 — collapse parser shadow stack into one PcgSlot array

The parser's typed shadow stack was three parallel arrays (cg_type_stack /
cg_value_flags / cg_lv_aux) shuffled in lockstep by grow/push/dup/swap/rot3.
Collapse them into a single PcgSlot{type; aux; flags} array (cg_slot_stack),
so the structural ops become single whole-slot copies/swaps and growth is one
allocation. All ~70 accessors in cg_adapter.c now index one array; no callers
outside cg_adapter.c touch the stack (I.3 already routed the parse_expr.c
pokes through pcg_retag_keep_flags).

Pure data-layout refactor, no behavior change: test-parse 3880+128/0,
test-toy 1392/0/35, test-cg-api 211/0 — identical to baseline.

Diffstat:
Mdoc/plan/TODO.md | 4----
Mlang/c/parse/cg_adapter.c | 143+++++++++++++++++++++++++++++++------------------------------------------------
Mlang/c/parse/cg_adapter.h | 15++++++++++++---
Mlang/c/parse/parse_priv.h | 4+---
4 files changed, 69 insertions(+), 97 deletions(-)

diff --git a/doc/plan/TODO.md b/doc/plan/TODO.md @@ -89,10 +89,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.) -- **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 - bridge — higher risk; needs care.) - **I.2 — two parallel C-6.7.9 initializer walkers** (`lang/c/parse/parse_init.c:648-777`) re-encode the same traversal grammar. Factor a single grammar driver + leaf vtable. - **I.4 — opt passes re-hand-roll the centralized operand-walk.** (The `ranges_overlap` diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -51,39 +51,26 @@ static void pcg_aux_clear(PcgLvAux* a) { } static void pcg_stack_grow(Parser* p, u32 want) { - const Type** ns; - u8* nf; - PcgLvAux* na; + PcgSlot* ns; u32 nc; if (p->cg_type_cap >= want) return; nc = p->cg_type_cap ? p->cg_type_cap * 2u : 64u; while (nc < want) nc *= 2u; - ns = arena_array(p->pool->arena, const Type*, nc); - if (!ns) perr(p, "out of memory in CG type stack"); - nf = arena_zarray(p->pool->arena, u8, nc); - if (!nf) perr(p, "out of memory in CG value stack"); - na = arena_zarray(p->pool->arena, PcgLvAux, nc); - if (!na) perr(p, "out of memory in CG lvalue aux stack"); - if (p->cg_type_stack && p->cg_type_sp) { - memcpy(ns, p->cg_type_stack, sizeof(*ns) * p->cg_type_sp); - } - if (p->cg_value_flags && p->cg_type_sp) { - memcpy(nf, p->cg_value_flags, sizeof(*nf) * p->cg_type_sp); - } - if (p->cg_lv_aux && p->cg_type_sp) { - memcpy(na, p->cg_lv_aux, sizeof(*na) * p->cg_type_sp); - } - p->cg_type_stack = ns; - p->cg_value_flags = nf; - p->cg_lv_aux = na; + ns = arena_zarray(p->pool->arena, PcgSlot, nc); + if (!ns) perr(p, "out of memory in CG shadow stack"); + if (p->cg_slot_stack && p->cg_type_sp) + memcpy(ns, p->cg_slot_stack, sizeof(*ns) * p->cg_type_sp); + p->cg_slot_stack = ns; p->cg_type_cap = nc; } void pcg_push_type(Parser* p, const Type* ty) { + PcgSlot* s; pcg_stack_grow(p, p->cg_type_sp + 1u); - p->cg_type_stack[p->cg_type_sp] = ty; - p->cg_value_flags[p->cg_type_sp] = 0; - pcg_aux_clear(&p->cg_lv_aux[p->cg_type_sp]); + s = &p->cg_slot_stack[p->cg_type_sp]; + s->type = ty; + s->flags = 0; + pcg_aux_clear(&s->aux); ++p->cg_type_sp; } @@ -92,51 +79,33 @@ void pcg_drop_type(Parser* p) { } void pcg_dup_type(Parser* p) { - const Type* ty = pcg_top_type(p); - u8 flags = p->cg_type_sp ? p->cg_value_flags[p->cg_type_sp - 1u] : 0; - PcgLvAux aux; - if (p->cg_type_sp) - aux = p->cg_lv_aux[p->cg_type_sp - 1u]; - else - pcg_aux_clear(&aux); - pcg_push_type(p, ty); + PcgSlot top; if (p->cg_type_sp) { - p->cg_value_flags[p->cg_type_sp - 1u] = flags; - p->cg_lv_aux[p->cg_type_sp - 1u] = aux; + top = p->cg_slot_stack[p->cg_type_sp - 1u]; + } else { + top.type = NULL; + top.flags = 0; + pcg_aux_clear(&top.aux); } + /* Copy the slot out before push: pcg_stack_grow may reallocate. */ + pcg_push_type(p, top.type); + if (p->cg_type_sp) p->cg_slot_stack[p->cg_type_sp - 1u] = top; } void pcg_swap_type(Parser* p) { if (p->cg_type_sp >= 2) { - const Type* a = p->cg_type_stack[p->cg_type_sp - 1u]; - u8 af = p->cg_value_flags[p->cg_type_sp - 1u]; - PcgLvAux ax = p->cg_lv_aux[p->cg_type_sp - 1u]; - p->cg_type_stack[p->cg_type_sp - 1u] = p->cg_type_stack[p->cg_type_sp - 2u]; - p->cg_value_flags[p->cg_type_sp - 1u] = - p->cg_value_flags[p->cg_type_sp - 2u]; - p->cg_lv_aux[p->cg_type_sp - 1u] = p->cg_lv_aux[p->cg_type_sp - 2u]; - p->cg_type_stack[p->cg_type_sp - 2u] = a; - p->cg_value_flags[p->cg_type_sp - 2u] = af; - p->cg_lv_aux[p->cg_type_sp - 2u] = ax; + PcgSlot tmp = p->cg_slot_stack[p->cg_type_sp - 1u]; + p->cg_slot_stack[p->cg_type_sp - 1u] = p->cg_slot_stack[p->cg_type_sp - 2u]; + p->cg_slot_stack[p->cg_type_sp - 2u] = tmp; } } void pcg_rot3_type(Parser* p) { if (p->cg_type_sp >= 3) { - const Type* a = p->cg_type_stack[p->cg_type_sp - 3u]; - u8 af = p->cg_value_flags[p->cg_type_sp - 3u]; - PcgLvAux ax = p->cg_lv_aux[p->cg_type_sp - 3u]; - p->cg_type_stack[p->cg_type_sp - 3u] = p->cg_type_stack[p->cg_type_sp - 2u]; - p->cg_value_flags[p->cg_type_sp - 3u] = - p->cg_value_flags[p->cg_type_sp - 2u]; - p->cg_lv_aux[p->cg_type_sp - 3u] = p->cg_lv_aux[p->cg_type_sp - 2u]; - p->cg_type_stack[p->cg_type_sp - 2u] = p->cg_type_stack[p->cg_type_sp - 1u]; - p->cg_value_flags[p->cg_type_sp - 2u] = - p->cg_value_flags[p->cg_type_sp - 1u]; - p->cg_lv_aux[p->cg_type_sp - 2u] = p->cg_lv_aux[p->cg_type_sp - 1u]; - p->cg_type_stack[p->cg_type_sp - 1u] = a; - p->cg_value_flags[p->cg_type_sp - 1u] = af; - p->cg_lv_aux[p->cg_type_sp - 1u] = ax; + PcgSlot a = p->cg_slot_stack[p->cg_type_sp - 3u]; + p->cg_slot_stack[p->cg_type_sp - 3u] = p->cg_slot_stack[p->cg_type_sp - 2u]; + p->cg_slot_stack[p->cg_type_sp - 2u] = p->cg_slot_stack[p->cg_type_sp - 1u]; + p->cg_slot_stack[p->cg_type_sp - 1u] = a; } } @@ -159,27 +128,27 @@ void pcg_drop(Parser* p) { } PcgLvAux* pcg_top_lv_aux(Parser* p) { - return p->cg_type_sp ? &p->cg_lv_aux[p->cg_type_sp - 1u] : NULL; + return p->cg_type_sp ? &p->cg_slot_stack[p->cg_type_sp - 1u].aux : NULL; } PcgLvAux* pcg_lv_aux_at(Parser* p, u32 depth) { - return (p->cg_type_sp > depth) ? &p->cg_lv_aux[p->cg_type_sp - 1u - depth] + return (p->cg_type_sp > depth) ? &p->cg_slot_stack[p->cg_type_sp - 1u - depth].aux : NULL; } const Type* pcg_top_type(Parser* p) { - return p->cg_type_sp ? p->cg_type_stack[p->cg_type_sp - 1u] : NULL; + return p->cg_type_sp ? p->cg_slot_stack[p->cg_type_sp - 1u].type : NULL; } const Type* pcg_top2_type(Parser* p) { - return p->cg_type_sp >= 2 ? p->cg_type_stack[p->cg_type_sp - 2u] : NULL; + return p->cg_type_sp >= 2 ? p->cg_slot_stack[p->cg_type_sp - 2u].type : NULL; } void pcg_retag_top(Parser* p, const Type* ty) { if (p->cg_type_sp) { - p->cg_type_stack[p->cg_type_sp - 1u] = ty; - p->cg_value_flags[p->cg_type_sp - 1u] = 0; - pcg_aux_clear(&p->cg_lv_aux[p->cg_type_sp - 1u]); + p->cg_slot_stack[p->cg_type_sp - 1u].type = ty; + p->cg_slot_stack[p->cg_type_sp - 1u].flags = 0; + pcg_aux_clear(&p->cg_slot_stack[p->cg_type_sp - 1u].aux); } } @@ -189,49 +158,49 @@ void pcg_retag_top(Parser* p, const Type* ty) { * changes (e.g. struct unqualification, narrowing a compound-assign LHS). */ void pcg_retag_keep_flags(Parser* p, u32 depth, const Type* ty) { if (p->cg_type_sp > depth) - p->cg_type_stack[p->cg_type_sp - 1u - depth] = ty; + p->cg_slot_stack[p->cg_type_sp - 1u - depth].type = ty; } int pcg_top_is_bitfield(Parser* p) { return p->cg_type_sp && - (p->cg_value_flags[p->cg_type_sp - 1u] & PCG_VALUE_BITFIELD) != 0; + (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_BITFIELD) != 0; } void pcg_set_top_bitfield(Parser* p) { if (p->cg_type_sp) - p->cg_value_flags[p->cg_type_sp - 1u] |= PCG_VALUE_BITFIELD; + p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_BITFIELD; } int pcg_top_is_register(Parser* p) { return p->cg_type_sp && - (p->cg_value_flags[p->cg_type_sp - 1u] & PCG_VALUE_REGISTER) != 0; + (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_REGISTER) != 0; } void pcg_set_top_register(Parser* p) { if (p->cg_type_sp) - p->cg_value_flags[p->cg_type_sp - 1u] |= PCG_VALUE_REGISTER; + p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_REGISTER; } int pcg_top_is_lvalue(Parser* p) { return p->cg_type_sp && - (p->cg_value_flags[p->cg_type_sp - 1u] & PCG_VALUE_LVALUE) != 0; + (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_LVALUE) != 0; } int pcg_top_is_modifiable_lvalue(Parser* p) { - return p->cg_type_sp && (p->cg_value_flags[p->cg_type_sp - 1u] & + return p->cg_type_sp && (p->cg_slot_stack[p->cg_type_sp - 1u].flags & (PCG_VALUE_LVALUE | PCG_VALUE_MODIFIABLE)) == (PCG_VALUE_LVALUE | PCG_VALUE_MODIFIABLE); } int pcg_top_is_null_ptr_const(Parser* p) { - return p->cg_type_sp && (p->cg_value_flags[p->cg_type_sp - 1u] & + return p->cg_type_sp && (p->cg_slot_stack[p->cg_type_sp - 1u].flags & PCG_VALUE_NULL_PTR_CONST) != 0; } void pcg_set_top_lvalue(Parser* p) { const Type* ty = pcg_top_type(p); if (p->cg_type_sp) - p->cg_value_flags[p->cg_type_sp - 1u] = pcg_lvalue_flags_for_type(ty); + p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(ty); } int pcg_emit_enabled(Parser* p) { return p && p->suppress_codegen == 0; } @@ -449,7 +418,7 @@ void pcg_push_int(Parser* p, i64 v, const Type* ty) { } pcg_push_type(p, ty); if (v == 0 && p->cg_type_sp) { - p->cg_value_flags[p->cg_type_sp - 1u] |= PCG_VALUE_NULL_PTR_CONST; + p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_NULL_PTR_CONST; } } @@ -488,8 +457,8 @@ void pcg_push_local_typed(Parser* p, FrameSlot s, const Type* ty) { if (pcg_emit_enabled(p)) kit_cg_push_local(p->cg, s); pcg_push_type(p, ty); if (p->cg_type_sp) { - p->cg_value_flags[p->cg_type_sp - 1u] = pcg_lvalue_flags_for_type(ty); - p->cg_lv_aux[p->cg_type_sp - 1u].base_kind = PCG_LV_BASE_LOCAL; + p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(ty); + p->cg_slot_stack[p->cg_type_sp - 1u].aux.base_kind = PCG_LV_BASE_LOCAL; } } @@ -501,8 +470,8 @@ void pcg_push_global(Parser* p, ObjSymId sym, const Type* ty) { if (pcg_emit_enabled(p)) kit_cg_push_symbol_addr(p->cg, sym, 0); pcg_push_type(p, ty); if (p->cg_type_sp) { - p->cg_value_flags[p->cg_type_sp - 1u] = pcg_lvalue_flags_for_type(ty); - p->cg_lv_aux[p->cg_type_sp - 1u].base_kind = PCG_LV_BASE_POINTER_RV; + p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(ty); + p->cg_slot_stack[p->cg_type_sp - 1u].aux.base_kind = PCG_LV_BASE_POINTER_RV; } } @@ -527,9 +496,9 @@ void pcg_load(Parser* p) { kit_cg_load(p->cg, access); } if (was_lvalue && p->cg_type_sp) { - p->cg_type_stack[p->cg_type_sp - 1u] = ty; - p->cg_value_flags[p->cg_type_sp - 1u] = 0; - pcg_aux_clear(&p->cg_lv_aux[p->cg_type_sp - 1u]); + p->cg_slot_stack[p->cg_type_sp - 1u].type = ty; + p->cg_slot_stack[p->cg_type_sp - 1u].flags = 0; + pcg_aux_clear(&p->cg_slot_stack[p->cg_type_sp - 1u].aux); } } @@ -736,8 +705,8 @@ void pcg_deref(Parser* p, const Type* pointee) { * pointer stays on the CG stack untouched. */ pcg_retag_top(p, pointee); if (p->cg_type_sp) { - p->cg_value_flags[p->cg_type_sp - 1u] = pcg_lvalue_flags_for_type(pointee); - p->cg_lv_aux[p->cg_type_sp - 1u].base_kind = PCG_LV_BASE_POINTER_RV; + p->cg_slot_stack[p->cg_type_sp - 1u].flags = pcg_lvalue_flags_for_type(pointee); + p->cg_slot_stack[p->cg_type_sp - 1u].aux.base_kind = PCG_LV_BASE_POINTER_RV; } } @@ -764,7 +733,7 @@ void pcg_lv_member(Parser* p, i64 byte_offset, const Type* field_ty, if (was_lvalue) { pcg_set_top_lvalue(p); } else if (base_is_rvalue_agg && p->cg_type_sp) { - p->cg_value_flags[p->cg_type_sp - 1u] = PCG_VALUE_LVALUE; + p->cg_slot_stack[p->cg_type_sp - 1u].flags = PCG_VALUE_LVALUE; } /* pcg_retag_top cleared aux; re-apply the bumped offset and base kind. */ { @@ -783,7 +752,7 @@ void pcg_lv_member(Parser* p, i64 byte_offset, const Type* field_ty, lv_after->is_subobject = 1u; } if (bf_width && p->cg_type_sp) - p->cg_value_flags[p->cg_type_sp - 1u] |= PCG_VALUE_BITFIELD; + p->cg_slot_stack[p->cg_type_sp - 1u].flags |= PCG_VALUE_BITFIELD; } } @@ -797,7 +766,7 @@ void pcg_lv_subscript(Parser* p, u32 elem_size, const Type* elem_ty) { i64 saved_offset = base_lv ? base_lv->offset : 0; u8 base_is_lvalue = (p->cg_type_sp >= 2u && - (p->cg_value_flags[p->cg_type_sp - 2u] & PCG_VALUE_LVALUE) != 0); + (p->cg_slot_stack[p->cg_type_sp - 2u].flags & PCG_VALUE_LVALUE) != 0); u8 saved_base_kind = !base_is_lvalue ? PCG_LV_BASE_POINTER_RV : (base_lv ? base_lv->base_kind : PCG_LV_BASE_LOCAL); diff --git a/lang/c/parse/cg_adapter.h b/lang/c/parse/cg_adapter.h @@ -5,8 +5,8 @@ * * Declares the `pcg_*` helpers (implemented in cg_adapter.c) plus the * C-frontend types they operate on. Every `pcg_*` call keeps the parser's - * typed shadow stack (cg_type_stack / cg_value_flags / cg_lv_aux in struct - * Parser) in lockstep with the public CG stack and folds C lvalue chains into + * typed shadow stack (cg_slot_stack in struct Parser, one PcgSlot per value) + * in lockstep with the public CG stack and folds C lvalue chains into * single effective-address memops; the parser never calls stack-affecting * `kit_cg_*` ops directly. See doc/FRONTENDS.md for the design. */ @@ -22,7 +22,7 @@ typedef KitCgLocal FrameSlot; #define FRAME_SLOT_NONE KIT_CG_LOCAL_NONE #define OBJ_GROUP_NONE 0u -/* Lvalue auxiliary state, carried parallel to cg_type_stack / cg_value_flags. +/* Lvalue auxiliary state, one per PcgSlot (the `aux` field). * * The C parser tracks one logical "C-language value" per stack slot. When that * slot is a C-language lvalue (PCG_VALUE_LVALUE), the aux below records the @@ -59,6 +59,15 @@ typedef struct PcgLvAux { u8 pad[5]; } PcgLvAux; +/* One shadow-stack slot: the CG type of a logical C value plus its parser-side + * value flags (PCG_VALUE_*) and lvalue aux, kept in lockstep with the CG value + * stack. The parser pushes/dups/swaps/rotates whole slots. */ +typedef struct PcgSlot { + const Type* type; + PcgLvAux aux; + u8 flags; +} PcgSlot; + typedef enum BinOp { BO_IADD, BO_ISUB, diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -214,9 +214,7 @@ typedef struct Parser { u8 default_visibility; /* SymVis */ u8 auto_var_init; /* KitAutoVarInit: implicit init for uninit locals */ - const Type** cg_type_stack; - u8* cg_value_flags; - PcgLvAux* cg_lv_aux; + PcgSlot* cg_slot_stack; u32 cg_type_sp; u32 cg_type_cap;