kit

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

commit d59dff083787fc4850bd4cf12191d01d0b773f33
parent 94e642e38295faa1c2724aaa0cd7a1d7ff0e4e2d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sat, 13 Jun 2026 21:35:21 -0700

perf(pp): pointer-replay no-paste function-like macro bodies (PERF §4.1 #3 Item A)

substitute_body ran subst_phase2 (a full extra body copy + re-walk) even for
no-`##` function-macro invocations, where phase 2 is the identity on phase-1
output once empty-arg placemarkers are elided.

When !m->has_paste, run phase 1 in a new no_paste mode straight into out and
skip phase 2. no_paste suppresses placemarker emission for an empty arg and
instead carries the empty arg's BOL/SPACE flags forward onto the next emitted
token — byte-identical to phase 2's placemarker-strip carry. With no
TOK_PP_PASTE in the body, adj_paste is always false and there is no paste work
to do. Stringize (#param) of an empty arg yields "" (a real token), not a
placemarker, so it is unaffected. A trailing carry is dropped, matching the
strip pass.

Removes one full-body copy per no-`##` function-macro invocation; arg
collection / pre-expansion (semantically required) are untouched.

Gate: perf-gate byte-identical (60/60); test-pp 110/0; sqlite -c object + -E
text byte-identical golden-vs-candidate; sqlite -E -6,577,024 Ir
(937,308,873 -> 930,731,849, -0.70%, best-of-7).

Diffstat:
Mlang/cpp/pp/pp_expand.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 66 insertions(+), 13 deletions(-)

diff --git a/lang/cpp/pp/pp_expand.c b/lang/cpp/pp/pp_expand.c @@ -770,10 +770,21 @@ static Tok paste_tokens(Pp* pp, Tok lhs, Tok rhs, SrcLoc loc) { /* Phase 1 (param substitution). For each parameter occurrence in the * body: if adjacent to ## or # (handled separately), substitute the raw * argument tokens; otherwise substitute the pre-expanded form. Empty raw - * args become a TOK_PP_PLACEMARKER which phase 2 collapses. */ -static void subst_phase1(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, - TokVec* out) { + * args become a TOK_PP_PLACEMARKER which phase 2 collapses. + * + * `no_paste` is the no-`##` fast path (set only when m->has_paste == 0, so the + * body provably has no TOK_PP_PASTE and adj_paste is always false): instead of + * emitting a placemarker for an empty arg, it accumulates the empty arg's + * BOL/SPACE flags into a `carry` and ORs them onto the NEXT emitted token — + * exactly what phase 2's placemarker-strip would do. The output is then already + * placemarker-free and identity under phase 2, so substitute_body can skip the + * second pass entirely. A trailing empty arg's carry has no surviving token to + * land on and is dropped, matching phase 2 (which leaves a trailing carry + * unused). */ +static void subst_phase1_impl(Pp* pp, const Macro* m, ArgList* a, + const Tok* invoke, TokVec* out, int no_paste) { u32 j; + u16 carry = 0; /* no_paste only: pending BOL/SPACE from stripped empty args */ /* Reserve a cheap upper bound up front so the per-expansion output vector * doesn't re-grow from cap 0 (0->8->16->32 doubling memcpys); arg expansion * may exceed it, which just falls back to the doubling. */ @@ -793,6 +804,10 @@ static void subst_phase1(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, Tok s = make_stringize(pp, a->raw, lo, hi, invoke->loc); s.flags = (u16)((s.flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | (bt->flags & (TF_AT_BOL | TF_HAS_SPACE))); + if (carry) { + s.flags |= carry; + carry = 0; + } tv_push(pp, out, s); ++j; continue; @@ -814,13 +829,20 @@ static void subst_phase1(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, } if (lo == hi) { - /* Empty argument → placemarker. */ - Tok pm; - memset(&pm, 0, sizeof(pm)); - pm.kind = TOK_PP_PLACEMARKER; - pm.flags = bt->flags & (TF_AT_BOL | TF_HAS_SPACE); - pm.loc = invoke->loc; - tv_push(pp, out, pm); + if (no_paste) { + /* No-`##` fast path: a placemarker only ever matters as a phase-2 + * strip carrier, so skip it and accumulate its BOL/SPACE for the + * next emitted token (identical to phase 2's strip carry). */ + carry |= bt->flags & (TF_AT_BOL | TF_HAS_SPACE); + } else { + /* Empty argument → placemarker. */ + Tok pm; + memset(&pm, 0, sizeof(pm)); + pm.kind = TOK_PP_PLACEMARKER; + pm.flags = bt->flags & (TF_AT_BOL | TF_HAS_SPACE); + pm.loc = invoke->loc; + tv_push(pp, out, pm); + } } else { u32 k; int first = 1; @@ -832,13 +854,34 @@ static void subst_phase1(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, (bt->flags & (TF_AT_BOL | TF_HAS_SPACE))); first = 0; } + if (carry) { + t.flags |= carry; + carry = 0; + } tv_push(pp, out, t); } } continue; } - tv_push(pp, out, *bt); + if (carry) { + Tok t = *bt; + t.flags |= carry; + carry = 0; + tv_push(pp, out, t); + } else { + tv_push(pp, out, *bt); + } } + /* A trailing carry (empty arg(s) at the very end with no following token) + * is dropped, matching phase 2: its strip pass leaves a trailing carry with + * no surviving token to OR onto. */ + (void)carry; +} + +/* Phase 1 in the general (placemarker-emitting) form; phase 2 follows. */ +static void subst_phase1(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, + TokVec* out) { + subst_phase1_impl(pp, m, a, invoke, out, /*no_paste=*/0); } /* Phase 2 (paste). Walk the post-substitute buffer; for each TOK_PP_PASTE, @@ -901,8 +944,18 @@ static void substitute_body(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, TokVec* out) { TokVec phase1 = {0}; u32 i; - subst_phase1(pp, m, a, invoke, &phase1); - subst_phase2(pp, phase1.data, phase1.n, invoke, out); + if (!m->has_paste) { + /* No `##` in the body: phase 2 (paste + placemarker strip) is the identity + * on phase-1 output once empty-arg placemarkers are elided. Run phase 1 in + * its no_paste mode straight into `out`, skipping the second full-body copy + * + re-walk. Byte-identical: no_paste carries empty-arg BOL/SPACE forward + * exactly as the strip pass would, and with no TOK_PP_PASTE there is no + * paste work to do. */ + subst_phase1_impl(pp, m, a, invoke, out, /*no_paste=*/1); + } else { + subst_phase1(pp, m, a, invoke, &phase1); + subst_phase2(pp, phase1.data, phase1.n, invoke, out); + } /* Invocation flags onto first emitted token. */ if (out->n) { out->data[0].flags =