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:
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