Fix overlay Clang exports, PGO, and scaffold cache

This commit is contained in:
Matthew Stanley
2026-09-10 17:20:27 -07:00
parent 3d10366fba
commit 2113defcfc
6 changed files with 74 additions and 26 deletions
+10 -1
View File
@@ -74,7 +74,16 @@ typedef struct CPUState {
* Static recompiled code and the interpreter share host cycle state directly,
* so their barrier compiles to nothing. */
#ifdef PSX_OVERLAY_DLL_BUILD
void overlay_flush_cycles(void);
/* Kept here rather than in psx_cycles.h because cpu_state.h is the first
* generated-code include that declares the store barrier. The preamble is
* inserted after all generated includes, so both declaration and definition
* must carry the same export attribute for Clang. */
# if defined(_WIN32)
# define PSX_OVERLAY_EXPORT __declspec(dllexport)
# else
# define PSX_OVERLAY_EXPORT __attribute__((visibility("default")))
# endif
PSX_OVERLAY_EXPORT void overlay_flush_cycles(void);
static inline void psx_store_cycle_barrier(void) { overlay_flush_cycles(); }
#else
static inline void psx_store_cycle_barrier(void) { }
@@ -4,12 +4,7 @@
static OverlayCallbacks g_cbs;
static uint32_t s_pending_cycles;
#ifdef _WIN32
__declspec(dllexport)
#else
__attribute__((visibility("default")))
#endif
void overlay_flush_cycles(void) {
PSX_OVERLAY_EXPORT void overlay_flush_cycles(void) {
uint32_t cycles = s_pending_cycles;
s_pending_cycles = 0;
if (cycles && g_cbs.advance_cycles) g_cbs.advance_cycles(cycles);
@@ -24,19 +19,11 @@ int *g_psx_call_bail_p = &s_bail_dummy;
uint64_t *g_psx_bail_first_p = &s_ctr_dummy0;
uint64_t *g_psx_bail_resolved_p = &s_ctr_dummy1;
#ifdef _WIN32
__declspec(dllexport)
#else
__attribute__((visibility("default")))
#endif
int overlay_abi(void) { return PSX_OVERLAY_ABI_VERSION | (PSX_OVERLAY_FLAVOR << 16); }
PSX_OVERLAY_EXPORT int overlay_abi(void) {
return PSX_OVERLAY_ABI_VERSION | (PSX_OVERLAY_FLAVOR << 16);
}
#ifdef _WIN32
__declspec(dllexport)
#else
__attribute__((visibility("default")))
#endif
void overlay_init(const OverlayCallbacks *cbs) {
PSX_OVERLAY_EXPORT void overlay_init(const OverlayCallbacks *cbs) {
g_cbs = *cbs;
if (g_cbs.call_bail_flag) g_psx_call_bail_p = g_cbs.call_bail_flag;
if (g_cbs.bail_first) g_psx_bail_first_p = g_cbs.bail_first;
+1 -1
View File
@@ -126,7 +126,7 @@ static inline void psx_advance_cycles(uint32_t cycles) {
/* Publish deferred charges (IRQ edge / MMIO / savestate). Overlay DLLs keep
* their pending total in the callback shim rather than these host globals. */
#if defined(PSX_OVERLAY_DLL_BUILD)
void overlay_flush_cycles(void);
PSX_OVERLAY_EXPORT void overlay_flush_cycles(void);
static inline void psx_cyc_local_publish(void) { }
static inline void psx_cyc_batch_flush(void) { overlay_flush_cycles(); }
#else
+50
View File
@@ -8,6 +8,13 @@ if(NOT DEFINED PSXRECOMP_ROOT)
get_filename_component(PSXRECOMP_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
endif()
# The rebuild CLI configures this as `generate` for its instrumented pass and
# `use` after it has merged the collected profile. Keep the switch here,
# beside the target it must affect: an otherwise unconsumed cache entry makes a
# costly PGO rebuild/train cycle a silent no-op.
set(PSX_PGO "" CACHE STRING "PGO mode: empty, generate, or use")
set_property(CACHE PSX_PGO PROPERTY STRINGS "" generate use)
include("${PSXRECOMP_ROOT}/cmake/psx_dependency_archive.cmake")
include("${PSXRECOMP_ROOT}/runtime/chd_dependency.cmake")
@@ -1359,6 +1366,49 @@ function(psxrecomp_add_runtime_target target)
# CMAKE_CXX_STANDARD; mod_packages.cpp must not compile as a pre-17 dialect.
target_compile_features(${target} PRIVATE c_std_11 cxx_std_17)
if(NOT PSX_PGO STREQUAL "")
if(NOT PSX_PGO STREQUAL "generate" AND NOT PSX_PGO STREQUAL "use")
message(FATAL_ERROR
"PSX_PGO must be empty, 'generate', or 'use' (got '${PSX_PGO}')")
endif()
set(_psx_pgo_dir "${CMAKE_BINARY_DIR}/pgo")
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(PSX_PGO STREQUAL "generate")
target_compile_options(${target} PRIVATE -fprofile-instr-generate)
target_link_options(${target} PRIVATE -fprofile-instr-generate)
else()
set(_psx_pgo_profile "${_psx_pgo_dir}/default.profdata")
target_compile_options(${target} PRIVATE
"-fprofile-instr-use=${_psx_pgo_profile}"
-Wno-profile-instr-out-of-date
-Wno-profile-instr-unprofiled)
target_link_options(${target} PRIVATE
"-fprofile-instr-use=${_psx_pgo_profile}")
endif()
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
# GCC writes .gcda files directly; run_pgo_train already recognizes
# those as a completed training run, so no llvm-profdata merge is
# required for this branch.
if(PSX_PGO STREQUAL "generate")
target_compile_options(${target} PRIVATE
"-fprofile-generate=${_psx_pgo_dir}")
target_link_options(${target} PRIVATE
"-fprofile-generate=${_psx_pgo_dir}")
else()
target_compile_options(${target} PRIVATE
"-fprofile-use=${_psx_pgo_dir}"
-Wno-missing-profile)
target_link_options(${target} PRIVATE
"-fprofile-use=${_psx_pgo_dir}")
endif()
else()
message(FATAL_ERROR
"PSX_PGO requires a Clang or GNU compiler (got ${CMAKE_C_COMPILER_ID})")
endif()
unset(_psx_pgo_dir)
unset(_psx_pgo_profile)
endif()
# Game-specific executable name. Every title instantiates this function with
# the same CMake target name ("psx-runtime"), so without this they ALL produce
# an identical "psx-runtime.exe" — launching or killing one title's process by
+3 -6
View File
@@ -2892,12 +2892,9 @@ def overlay_pair_id(src: str, func_ids: list,
def add_overlay_pair_export(src: str, pair_id: int) -> str:
"""Add the optional v2-pair binding export without changing the shard ABI."""
return src + f'''\n
#ifdef _WIN32
__declspec(dllexport)
#else
__attribute__((visibility("default")))
#endif
uint64_t overlay_pair_id(void) {{ return UINT64_C(0x{pair_id:016X}); }}
PSX_OVERLAY_EXPORT uint64_t overlay_pair_id(void) {{
return UINT64_C(0x{pair_id:016X});
}}
'''
+5
View File
@@ -572,6 +572,11 @@ def render_game_toml(p: DiscProbe, *, disc_rel: str, out_dir: str, players: int,
"[runtime]",
'window_title = "' + toml_escape(p.display_name + " Recompiled") + '"',
'memcard_dir = "saves"',
# Enable captured dirty-RAM overlays by default. A freshly probed
# project otherwise never initializes the cache pipeline and silently
# interprets every runtime-loaded overlay until a maintainer discovers
# and adds this setting by hand.
"overlay_cache = true",
"",
"[video]",
'renderer = "opengl"',