kit

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

commit 2ea9a8b5413b8c1995264ec8c2e9b5aaaf36dfda
parent 4501d77e4915f2b6d863c0261d53e4436dfca962
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 12 Jun 2026 10:03:06 -0700

feat(c): add __sync_synchronize (legacy GCC full memory barrier)

The legacy __sync_* atomic builtin for a sequentially-consistent full fence,
with no operands and no result. Lowers to the existing seq-cst fence primitive
(pcg_fence), mirroring the __atomic_thread_fence path. SQLite's
sqlite3MemoryBarrier() emits it on any __GNUC__ compiler, so it was the sole
blocker to compiling the unmodified sqlite3.c amalgamation.

Diffstat:
Mlang/c/parse/parse.c | 2++
Mlang/c/parse/parse_expr.c | 13++++++++++++-
Mlang/c/parse/parse_priv.h | 1+
Atest/parse/cases/builtin_26_sync_synchronize.c | 11+++++++++++
Atest/parse/cases/builtin_26_sync_synchronize.expected | 1+
5 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -1765,6 +1765,8 @@ void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg, kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_thread_fence")); p.sym_a_signal_fence = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_signal_fence")); + p.sym_sync_synchronize = + kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__sync_synchronize")); p.scope = scope_new(&p, NULL); diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -1812,7 +1812,8 @@ static int try_parse_builtin_call(Parser* p) { name != p->sym_a_fetch_or && name != p->sym_a_fetch_xor && name != p->sym_a_fetch_nand && name != p->sym_a_cas_n && name != p->sym_a_always_lock_free && name != p->sym_a_is_lock_free && - name != p->sym_a_thread_fence && name != p->sym_a_signal_fence) { + name != p->sym_a_thread_fence && name != p->sym_a_signal_fence && + name != p->sym_sync_synchronize) { return 0; } advance(p); /* IDENT */ @@ -1980,6 +1981,16 @@ static int try_parse_builtin_call(Parser* p) { return 1; } + /* __sync_synchronize(): the legacy GCC full barrier. No operands; always a + * sequentially-consistent fence (the __sync_* family is implicitly seq-cst). */ + if (name == p->sym_sync_synchronize) { + expect_punct(p, ')', "')' after __sync_synchronize"); + pcg_set_loc(p, loc); + pcg_fence(p, MO_SEQ_CST); + pcg_push_int(p, 0, ty_int(p)); + return 1; + } + if (name == p->sym_a_always_lock_free || name == p->sym_a_is_lock_free) { i64 size = eval_const_int(p, p->cur.loc); expect_punct(p, ',', "',' in atomic lock-free builtin"); diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -328,6 +328,7 @@ typedef struct Parser { Sym sym_a_is_lock_free; Sym sym_a_thread_fence; Sym sym_a_signal_fence; + Sym sym_sync_synchronize; /* __sync_synchronize (legacy full barrier) */ Scope* scope; /* name -> current file-scope function entry. Replaces what was an O(n) linear diff --git a/test/parse/cases/builtin_26_sync_synchronize.c b/test/parse/cases/builtin_26_sync_synchronize.c @@ -0,0 +1,11 @@ +/* __sync_synchronize() is the legacy GCC full (sequentially-consistent) memory + * barrier: no operands, no result. SQLite uses it for sqlite3MemoryBarrier(). + * Single-threaded it has no observable effect, so we just confirm it parses, + * lowers to a fence, and the surrounding arithmetic still runs. */ +int test_main(void) { + int x = 21; + __sync_synchronize(); + x = x * 2; + __sync_synchronize(); + return x; +} diff --git a/test/parse/cases/builtin_26_sync_synchronize.expected b/test/parse/cases/builtin_26_sync_synchronize.expected @@ -0,0 +1 @@ +42