libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
xtc_tailcall.h
1/*-
2 * Copyright (c) 2026, The XTC Project
3 * @stability experimental
4 * Use of this source code is governed by the ISC License.
5 *
6 * src/inc/xtc_tailcall.h
7 * Mark functions/call-sites as MUST-be-tail-called. GCC and
8 * Clang both perform tail-call optimization (TCO) when the
9 * last operation in a function is a call to another function
10 * whose return value is also returned. We document the
11 * intent at the call site so a script can verify that the
12 * compiler actually emitted a `jmp` (or arch-equivalent) and
13 * not a `call` followed by `ret`.
14 *
15 * Usage:
16 * - At a call-site that MUST be tail-called for correctness
17 * (e.g. avoiding stack growth in a deep dispatch chain),
18 * annotate via XTC_MUSTTAIL:
19 *
20 * return XTC_MUSTTAIL fn(args);
21 *
22 * - GCC's `__attribute__((musttail))` (15+) and Clang's
23 * `[[clang::musttail]]` are honored. On older toolchains
24 * we fall back to `__attribute__((always_inline))` of a
25 * helper that returns directly.
26 *
27 * Validation:
28 * scripts/check-tailcalls.sh disassembles the static lib
29 * and confirms each annotated site is a `jmp` not a `call`.
30 * Run via `make check-tailcalls`.
31 *
32 * When TCO matters in xtc:
33 * - State-machine dispatch: handler returning a tail-call to
34 * the next state's handler (e.g. parse trees).
35 * - Scheduler dispatch: loop's task-step jumping into the
36 * coroutine entry without growing the loop's stack.
37 * - Lock-free fast paths where one inline helper jumps to
38 * the slow path on miss.
39 */
40
41#ifndef XTC_TAILCALL_H
42#define XTC_TAILCALL_H
43
44/* musttail is a *statement* attribute, not a function attribute.
45 * Both clang's `[[clang::musttail]]` and gcc-15's
46 * `__attribute__((musttail))` are accepted as statement attributes,
47 * but only in compilers that parse C2x bracket attributes (clang)
48 * or have GCC 15's extension. In strict C11 mode -- which xtc uses --
49 * we fall back to a no-op and rely on the optimizer. The
50 * `scripts/check-tailcalls.sh` validator inspects the .o to confirm
51 * `jmp` was emitted regardless. */
52/* XTC_MUSTTAIL is a marker; it's prefixed to a function call inside
53 * a return statement to signal intent. In gcc 15+ and clang's C2x
54 * mode the attribute can be attached to the return statement itself
55 * (`__attribute__((musttail)) return foo();`) but the syntactic
56 * position varies enough across toolchains that we keep the macro
57 * as a no-op universally and rely on:
58 * 1. the -O2 optimizer doing TCO when it can, and
59 * 2. scripts/check-tailcalls.sh validating the .o emitted `jmp`.
60 * When compiler enforcement matters more than convenience, callers
61 * can use the explicit form directly. */
62#define XTC_MUSTTAIL /* no-op marker; see check-tailcalls.sh */
63
64/* Marker macro for the validator script: annotated call sites
65 * become a #pragma comment that survives into the disassembly's
66 * line metadata. */
67#if defined(XTC_TAILCALL_MARK_SITES)
68# define XTC_TAIL_CALL(expr) \
69 (__extension__ ({ \
70 _Pragma("message \"xtc-tailcall-marker\""); \
71 XTC_MUSTTAIL expr; \
72 }))
73#else
74# define XTC_TAIL_CALL(expr) (XTC_MUSTTAIL expr)
75#endif
76
77#endif /* XTC_TAILCALL_H */