From d490451909b7557b1d8a2c8901a9ac6d4362b847 Mon Sep 17 00:00:00 2001 From: dougchansan Date: Thu, 6 Aug 2026 10:46:53 -1000 Subject: [PATCH 1/2] module-template: fix the IPO check, and default IPO off The IPO support check could never pass on macOS, and the failure was silent. moderngekko-port configures with CMAKE_NINJA_FORCE_RESPONSE_FILE=1, which the module genuinely needs -- 186 objects do not fit on a command line. check_ipo_supported's try-compile inherits the environment, so its static library step runs `ar qc libfoo.a @foo.rsp`, and Apple's /usr/bin/ar has no @file support: ar: @CMakeFiles/foo.rsp: No such file or directory The check therefore failed, CMake logged one "Module IPO disabled:" line, and the build carried on without -flto=thin -- while manifest.txt went on recording `flags=compile:-O2 -flto=thin ... link:-flto=thin`. Object files were plain Mach-O rather than LLVM bitcode. No module built on macOS has ever had cross-translation-unit inlining, which is worth knowing before drawing any conclusion about why a runtime helper did not get inlined into generated code. Scope the variable off around the check only and restore it before the generator reads it, so the real link keeps its response files. Also flip RECOMPCORE_MODULE_ENABLE_IPO to OFF, because with the check repaired LTO was measured and did not pay. Mario Kart: Double Dash on arm64, same PGO profile, only -flto=thin differing, alternating A/B with a reversed final block on one savestate: no LTO n=5 mean 1.1826 [1.1729-1.1959] LTO n=5 mean 1.1733 [1.1387-1.1879] -0.8%, ranges overlap -- unproven The host was not quiet, so this is "no win" rather than "a loss". Pushing further -- -Wl,-mllvm,-import-instr-limit=500 -Wl,-mllvm,-inline-threshold=600, which does inline the hot FP helper, taking ppc_fmuls from 5846 call sites to 861 -- measured -1.7% and grew the module by 7 MB. One caveat on the default. On Linux, GNU ar does support @file, so the check presumably passed there and those builds have had thin-LTO all along; OFF takes it away from them. That is not backed by a Linux measurement. If you would rather not change Linux, take the check fix and drop the default change -- they are independent, and the option can still be set per build. --- module-template/CMakeLists.txt | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/module-template/CMakeLists.txt b/module-template/CMakeLists.txt index 2757a8d96d..2043a3e6b7 100644 --- a/module-template/CMakeLists.txt +++ b/module-template/CMakeLists.txt @@ -120,7 +120,17 @@ if(UNIX AND NOT APPLE) "${CMAKE_CURRENT_SOURCE_DIR}/module.exports") endif() -option(RECOMPCORE_MODULE_ENABLE_IPO "Enable Clang module interprocedural optimization when supported" ON) +# Off by default because it was measured and it did not pay. On MKDD/arm64, +# same PGO profile, only -flto=thin differing, alternating A/B on one scene: +# 1.1826 without against 1.1733 with, i.e. -0.8% with overlapping ranges. It +# also makes the link markedly slower. Turn it on with -D...=ON to re-measure. +# +# It was ON here for a long time and did nothing on macOS anyway: the support +# check below could not pass. See the comment on it. Anyone who was getting IPO +# before -- Linux builds, where GNU ar makes the check succeed -- loses it with +# this default, which is a deliberate choice and not a measured one on that +# platform. +option(RECOMPCORE_MODULE_ENABLE_IPO "Enable Clang module interprocedural optimization when supported" OFF) set(RECOMPCORE_MODULE_OPT_LEVEL "2" CACHE STRING "Optimization level for generated module translation units (0, 1, 2, or 3)") set_property(CACHE RECOMPCORE_MODULE_OPT_LEVEL PROPERTY STRINGS 0 1 2 3) @@ -130,8 +140,22 @@ if(NOT RECOMPCORE_MODULE_OPT_LEVEL MATCHES "^[0-3]$") endif() if(RECOMPCORE_MODULE_ENABLE_IPO AND CMAKE_C_COMPILER_ID MATCHES "Clang") include(CheckIPOSupported) + # moderngekko-port configures with CMAKE_NINJA_FORCE_RESPONSE_FILE=1, which the + # module needs: it links thousands of chunk objects and the command line does + # not fit in ARG_MAX. But check_ipo_supported's try-compile inherits the + # environment, and its static-library step then runs `ar qc libfoo.a @foo.rsp` + # -- Apple's /usr/bin/ar has no @file support, so the check fails with + # "ar: @CMakeFiles/foo.rsp: No such file or directory" and IPO is silently + # disabled. The manifest still records -flto=thin. Every module built this way + # had NO cross-translation-unit inlining. Scope the variable off for the check + # only, then restore it before the generator reads it. + set(_module_forced_rsp "$ENV{CMAKE_NINJA_FORCE_RESPONSE_FILE}") + unset(ENV{CMAKE_NINJA_FORCE_RESPONSE_FILE}) check_ipo_supported(RESULT RECOMPCORE_MODULE_IPO_SUPPORTED OUTPUT RECOMPCORE_MODULE_IPO_ERROR LANGUAGES C) + if(_module_forced_rsp) + set(ENV{CMAKE_NINJA_FORCE_RESPONSE_FILE} "${_module_forced_rsp}") + endif() if(RECOMPCORE_MODULE_IPO_SUPPORTED) set_property(TARGET ${MODULE_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) else() From a8a795bd7687fe9a639d348d7844a7690c2b0b9f Mon Sep 17 00:00:00 2001 From: jw <183880766+siahisaforker@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:52:59 -0700 Subject: [PATCH 2/2] Keep IPO enabled --- module-template/CMakeLists.txt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/module-template/CMakeLists.txt b/module-template/CMakeLists.txt index 2043a3e6b7..3b00450722 100644 --- a/module-template/CMakeLists.txt +++ b/module-template/CMakeLists.txt @@ -120,17 +120,7 @@ if(UNIX AND NOT APPLE) "${CMAKE_CURRENT_SOURCE_DIR}/module.exports") endif() -# Off by default because it was measured and it did not pay. On MKDD/arm64, -# same PGO profile, only -flto=thin differing, alternating A/B on one scene: -# 1.1826 without against 1.1733 with, i.e. -0.8% with overlapping ranges. It -# also makes the link markedly slower. Turn it on with -D...=ON to re-measure. -# -# It was ON here for a long time and did nothing on macOS anyway: the support -# check below could not pass. See the comment on it. Anyone who was getting IPO -# before -- Linux builds, where GNU ar makes the check succeed -- loses it with -# this default, which is a deliberate choice and not a measured one on that -# platform. -option(RECOMPCORE_MODULE_ENABLE_IPO "Enable Clang module interprocedural optimization when supported" OFF) +option(RECOMPCORE_MODULE_ENABLE_IPO "Enable Clang module interprocedural optimization when supported" ON) set(RECOMPCORE_MODULE_OPT_LEVEL "2" CACHE STRING "Optimization level for generated module translation units (0, 1, 2, or 3)") set_property(CACHE RECOMPCORE_MODULE_OPT_LEVEL PROPERTY STRINGS 0 1 2 3)