kit

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

commit 7ada3f622cc608f4a05db5a87ea9d5e88623f39d
parent 209596b8a0efc2568c32863ca6990825240d26f1
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sat, 13 Jun 2026 11:42:56 -0700

perf(pp): replay no-## macro bodies by pointer, skip 2 copies/expansion (A3)

(cherry picked from commit 63b977a44b0ec25624f25c879d2a9d2941cce7a2)

Diffstat:
Mlang/cpp/pp/pp.c | 31+++++++++++++++++++++++++++++++
Mlang/cpp/pp/pp_expand.c | 25+++++++++++++++++++++++++
Mlang/cpp/pp/pp_priv.h | 24++++++++++++++++++++++--
3 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/lang/cpp/pp/pp.c b/lang/cpp/pp/pp.c @@ -77,6 +77,15 @@ void src_next_raw_into(Pp* pp, Tok* out, HidesetId* hs_out, u8* src_kind_out) { *out = s->toks[s->i]; if (hs_out) *hs_out = s->hs ? s->hs[s->i] : s->hs_uniform; if (src_kind_out) *src_kind_out = SRC_BUF; + /* Pointer-replayed body: apply the per-invocation loc and (first token + * only) BOL/SPACE flags the old fresh-copy path baked in. */ + if (s->has_loc_override) { + if (s->i == 0) { + out->flags = (u16)((out->flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | + s->first_flags_or); + } + out->loc = s->loc_override; + } ++s->i; return; } @@ -175,6 +184,28 @@ void push_buf_uniform(Pp* pp, Tok* toks, u32 n, HidesetId hs_uniform) { src_push(pp, s); } +/* Push an immutable token buffer (a no-`##` macro body) for pointer-replay. + * The const-cast on `toks` is sound: replay is strictly read-only — the two + * read sites (src_next_raw_into, the pp_pull_into fast path) load each token by + * value and never write back through s->toks. The per-read loc/flags override + * (has_loc_override) reproduces the mutations the old fresh-copy path baked in, + * so the shared body is surfaced byte-for-byte without copying it. */ +void push_buf_replay(Pp* pp, const Tok* toks, u32 n, HidesetId hs_uniform, + SrcLoc loc_override, u16 first_flags_or) { + TokSrc s; + memset(&s, 0, sizeof(s)); + s.kind = SRC_BUF; + s.toks = (Tok*)toks; + s.hs = NULL; + s.hs_uniform = hs_uniform; + s.has_loc_override = 1; + s.loc_override = loc_override; + s.first_flags_or = first_flags_or; + s.i = 0; + s.n = n; + src_push(pp, s); +} + /* ============================================================ * Public streaming entries * ============================================================ */ diff --git a/lang/cpp/pp/pp_expand.c b/lang/cpp/pp/pp_expand.c @@ -261,6 +261,7 @@ void do_define(Pp* pp, const Tok* line, u32 n) { m->body_len = body_n; for (j = 0; j < body_n; ++j) { Tok t = line[i + j]; + if (t.kind == TOK_PP_PASTE) m->has_paste = 1; if (m->is_func && t.kind == TOK_IDENT) { u32 p; for (p = 0; p < m->n_params; ++p) { @@ -369,6 +370,20 @@ static void expand_object_macro(Pp* pp, const Macro* m, const Tok* invoke, if (m->body_len == 0) { return; /* placemarker: nothing to push */ } + /* No `##`: an object body has no params and no placemarkers, so the paste + * phase is a pure identity copy. Skip both copies — replay the immutable + * definition-time m->body by pointer, applying the per-invocation loc and + * first-token flag transfer at read time (push_buf_replay). Byte-identical + * to the slow path (same tokens, same loc, same first-token flags), with + * zero per-invocation token copies or body allocs. */ + if (!m->has_paste) { + u16 ff = (u16)((m->body[0].flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | + (invoke->flags & (TF_AT_BOL | TF_HAS_SPACE))); + hs = hs_add(pp, invoke_hs, m->name); + push_buf_replay(pp, m->body, m->body_len, hs, invoke->loc, ff); + return; + } + /* Run the body through the paste phase: object-like macros may use * `##`. There are no parameters, so phase 1 reduces to a copy. */ tmp = arena_array(pp->xarena, Tok, m->body_len); @@ -980,6 +995,16 @@ static void pp_pull_into(Pp* pp, Tok* out, int skip_nl) { *out = s->toks[s->i]; hs = s->hs ? s->hs[s->i] : s->hs_uniform; src_kind = SRC_BUF; + /* Pointer-replayed body: apply the per-invocation loc and (first token + * only) BOL/SPACE flags the old fresh-copy path baked in. Identical to + * the slow read site in src_next_raw_into so both paths agree. */ + if (s->has_loc_override) { + if (s->i == 0) { + out->flags = (u16)((out->flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | + s->first_flags_or); + } + out->loc = s->loc_override; + } ++s->i; } else { src_next_raw_into(pp, out, &hs, &src_kind); diff --git a/lang/cpp/pp/pp_priv.h b/lang/cpp/pp/pp_priv.h @@ -30,7 +30,11 @@ typedef struct Macro { SrcLoc def_loc; u8 is_func; u8 is_variadic; - u8 pad[2]; + /* Pure cache of the body (NOT part of macro identity): 1 iff the body + * contains at least one TOK_PP_PASTE (`##`). Lets a no-`##` body be + * replayed by pointer without the per-invocation copy + paste pass. */ + u8 has_paste; + u8 pad[1]; u32 n_params; Sym* params; /* parameter names */ Tok* body; /* body tokens; TOK_PP_PARAM kind + v.punct=idx */ @@ -75,7 +79,16 @@ typedef struct TokSrc { * (e.g. argument pre-expansion) explicitly pops the scope when done. * This bounds expansion to a single argument's token stream. */ u8 scope_top; - u8 pad[2]; + /* Read-time loc/flags override for a pointer-replayed macro body (SRC_BUF). + * When has_loc_override, every token read from this buffer gets + * out->loc = loc_override, and the FIRST token (s->i == 0 at read) also has + * its BOL/SPACE bits replaced by first_flags_or. This reproduces the + * mutations expand_object_macro used to bake into a fresh body copy, so the + * immutable definition-time m->body can be replayed in place. 0 = no + * override (every push_buf/push_buf_uniform memsets the whole TokSrc). */ + u8 has_loc_override; + u8 pad[1]; + u16 first_flags_or; /* SRC_LEX */ Lexer* lex; /* SRC_BUF */ @@ -88,6 +101,8 @@ typedef struct TokSrc { * (no alloc, no fill, one scalar instead of n copies). */ HidesetId* hs; HidesetId hs_uniform; + /* Per-token loc applied when has_loc_override (see scope_top block). */ + SrcLoc loc_override; u32 i; u32 n; /* #line state (SRC_LEX only). line_delta is added to every emitted @@ -415,6 +430,11 @@ void src_push(Pp* pp, TokSrc s); void src_pop(Pp* pp); void push_buf(Pp* pp, Tok* toks, HidesetId* hs, u32 n); void push_buf_uniform(Pp* pp, Tok* toks, u32 n, HidesetId hs_uniform); +/* Push an immutable, read-only token buffer (e.g. a no-`##` macro body) for + * pointer-replay. The buffer is never written through s->toks; per-read + * loc/flags overrides reproduce the mutations the old body-copy path baked in. */ +void push_buf_replay(Pp* pp, const Tok* toks, u32 n, HidesetId hs_uniform, + SrcLoc loc_override, u16 first_flags_or); /* pp_next_raw is the mutual-recursion entry: expand_arg_to_eof calls it, * and pp_next_raw drives directives and expansion. Declared non-static so