diff options
| author | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-08-22 22:27:33 +0200 |
|---|---|---|
| committer | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-08-22 22:27:33 +0200 |
| commit | 2e097cec409182c3cb39b74489387480bf8a278f (patch) | |
| tree | 47f501fa2634835cc0c70a9214f01b32f49b9d30 /src/parser.c | |
| parent | 3ae89e34f6a04dd553f3871856521334a4dbe62f (diff) | |
optimize main state machine transitions with tail calls
* On newer GCC (>= 15) and Clang (>= 13) versions we can tail call
at the end of input_cb() implementations to the next state's input_cb(),
which will be optimized to jumps (often direct jumps).
That is, the compilers always optimized tail calls, but we can
guarantee tail calls with the __attribute__((musttail)) statement
attribute.
* Every `return &teco_state_xxx` has to be replaced with
`TECO_RETURN(ctx, &teco_state_xxx, error)`.
* This speeds up `-O2 -flto` builds by 18%
(e.g. tested on grosciteco for sciteco(7)).
Part of the speed up could also be because of inlining through
TECO_RETURN().
* The other state machines (stringbuilding and q-reg spec) cannot
currently be optimized the same way since they get their characters
passed in from the "main" state machine.
* All loops around callbacks could be optimized the same way.
E.g. the undo token runner could also tail call into the next runner,
but it's probably not important to optimize undo token executions.
Diffstat (limited to 'src/parser.c')
| -rw-r--r-- | src/parser.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/src/parser.c b/src/parser.c index 8b02764..8ec051e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -104,6 +104,9 @@ teco_machine_main_step(teco_machine_main_t *ctx, const gchar *macro, gsize stop_ { gsize last_pc = 0; + ctx->macro = macro; + ctx->stop_pos = stop_pos; + while (ctx->macro_pc < stop_pos) { last_pc = ctx->macro_pc; @@ -1091,7 +1094,7 @@ teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar chr, GError **e * as allowing whitespace escape_chars is harmful. */ if (ctx->flags.modifier_at && teco_is_noop(chr)) - return current; + TECO_RETURN(ctx, current, error); /* * String termination handling @@ -1106,7 +1109,7 @@ teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar chr, GError **e if (ctx->parent.must_undo) teco_undo_gunichar(ctx->expectstring.machine.escape_char); ctx->expectstring.machine.escape_char = g_unichar_toupper(chr); - return current; + TECO_RETURN(ctx, current, error); } /* @@ -1177,7 +1180,7 @@ teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar chr, GError **e if (ctx->parent.must_undo) teco_undo_gsize(ctx->expectstring.insert_len); ctx->expectstring.insert_len = 0; - return next; + TECO_RETURN(ctx, next, error); } /* @@ -1213,7 +1216,7 @@ teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar chr, GError **e teco_undo_gsize(ctx->expectstring.insert_len); ctx->expectstring.insert_len += ctx->expectstring.string.len - old_len; - return current; + TECO_RETURN(ctx, current, error); } gboolean |
