Files
psxrecomp/runtime/src/overlay_backend.c
T
Matthew Stanley c2a3f6ad79 overlay: add tcc tier (toolchain-free fallback) replacing sljit; extract overlay_backend
Compiler-neutral tier-selection policy extracted from the mis-named
overlay_sljit.{c,h} into NEW overlay_backend.{c,h} (OverlayBackend enum +
resolve/name/active). overlay_sljit.{c,h} is now just the deprecated emitter.

New tcc tier. gcc and tcc run the IDENTICAL pipeline (recompiler -> C ->
compiler -> DLL -> loader); only the compiler binary differs, so both map to the
autocompile-spawn provider (code_provider.c) and the COMMAND is chosen by the
resolved backend (main.cpp). compile_overlays.py gains --compiler gcc|tcc: tcc
writes a separate tcc/ cache namespace, BOM-strips the C + a copy of the include
headers (tcc 0.9.27 can't skip a UTF-8 BOM), and uses tcc's built-in linker.

Backends (overlay_backend): auto (gcc if a gcc TOOLCHAIN is present, else tcc --
was sljit), gcc, tcc, auto-no-gcc (dev/test: force tcc even with gcc present, to
exercise the toolchain-less user path), sljit (DEPRECATED, gated off, lowest).
Priority: static > gcc shard > tcc shard > sljit(off) > interp. The loader scans
gcc/ then tcc/ and dedups by region+crc (filename) so a gcc shard always wins a
tie.

Self-contained tcc: with no explicit overlay_autocompile_cmd_tcc, the runtime
CONSTRUCTS the tcc command from a toolchain bundled beside the exe
(<exe>/overlay_toolchain/: embedded python + tcc + recompiler + compile_overlays.py
+ runtime headers) -- no system python or gcc needed. config_loader gains
overlay_autocompile_cmd_tcc (a dev override). autocompile cmd buffers enlarged for
the constructed path-heavy command.

Compilation stays OFF the dispatch/render thread (off-process autocompile
subprocess, same model as gcc); the main thread only spawns it and dlopens the
finished DLL.

Validated: MMX6 with overlay_backend=auto-no-gcc fills the tcc/ namespace live
from the bundled toolchain and plays through save-load + gameplay -- the exact
path the sljit tier softlocked on. The gcc path is untouched.

Runtime-only, no regen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 13:10:57 -07:00

67 lines
2.7 KiB
C

/* overlay_backend.c — compiler-neutral overlay tier-selection policy.
* See overlay_backend.h. Moved out of overlay_sljit.c (which is now just the
* deprecated sljit emitter): deciding gcc vs tcc vs sljit is not sljit's job. */
#include "overlay_backend.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
static OverlayBackend s_active = OVERLAY_BACKEND_AUTO;
static int s_resolved = 0;
static char s_last_msg[256];
static void backend_log(const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
vsnprintf(s_last_msg, sizeof(s_last_msg), fmt, ap);
va_end(ap);
}
const char *overlay_backend_name(OverlayBackend b) {
switch (b) {
case OVERLAY_BACKEND_GCC: return "gcc";
case OVERLAY_BACKEND_SLJIT: return "sljit";
case OVERLAY_BACKEND_TCC: return "tcc";
case OVERLAY_BACKEND_AUTO_NO_GCC: return "auto-no-gcc";
default: return "auto";
}
}
static OverlayBackend parse_backend(const char *s, OverlayBackend dflt) {
if (!s || !*s) return dflt;
if (!strcmp(s, "gcc")) return OVERLAY_BACKEND_GCC;
if (!strcmp(s, "sljit")) return OVERLAY_BACKEND_SLJIT;
if (!strcmp(s, "tcc")) return OVERLAY_BACKEND_TCC;
if (!strcmp(s, "auto-no-gcc")) return OVERLAY_BACKEND_AUTO_NO_GCC;
if (!strcmp(s, "auto")) return OVERLAY_BACKEND_AUTO;
return dflt;
}
OverlayBackend overlay_backend_resolve(const char *cfg, int gcc_toolchain_available) {
/* Precedence: env PSX_OVERLAY_BACKEND > game.toml [runtime] overlay_backend
* (cfg) > AUTO. Tier order is static > gcc > tcc > (sljit, deprecated/off) >
* interp. AUTO prefers gcc when a gcc TOOLCHAIN is actually present (a dev /
* production box), else tcc (the bundled toolchain-free user fallback).
* AUTO_NO_GCC forces the tcc branch even when gcc IS present — it simulates a
* toolchain-less user box on a dev machine (gcc shards still LOAD via the
* loader; only the gap-fill compiler is forced to tcc). */
OverlayBackend want = parse_backend(getenv("PSX_OVERLAY_BACKEND"),
parse_backend(cfg, OVERLAY_BACKEND_AUTO));
OverlayBackend eff = want;
if (want == OVERLAY_BACKEND_AUTO)
eff = gcc_toolchain_available ? OVERLAY_BACKEND_GCC : OVERLAY_BACKEND_TCC;
else if (want == OVERLAY_BACKEND_AUTO_NO_GCC)
eff = OVERLAY_BACKEND_TCC;
s_active = eff;
s_resolved = 1;
backend_log("backend resolved: want=%s effective=%s (gcc_toolchain=%d)",
overlay_backend_name(want), overlay_backend_name(eff),
gcc_toolchain_available);
return eff;
}
OverlayBackend overlay_backend_active(void) { return s_active; }