From c36cff8937ae2a370cc2ea76d48c11be616dbb6a Mon Sep 17 00:00:00 2001 From: Harmenszoon <25753539+Harmenszoon@users.noreply.github.com> Date: Mon, 11 May 2026 14:41:30 -0400 Subject: [PATCH] [Build] enable IPO/LTO for release builds (opt-out via -DSC_ENABLE_LTO=OFF) Adds SC_ENABLE_LTO, default ON, and uses check_ipo_supported() to enable target-level IPO/LTO only for non-Debug configurations. Unsupported toolchains emit a status message and continue without IPO/LTO. Initial no-code A/B on MSVC 19.44.35217.0, CMake 3.31.6, Ninja, Release BUILD_GUI=OFF compared baseline /O2 /Ob2 /DNDEBUG against IPO /GL + /LTCG with threads=1 target_error=0 deterministic=1 fixed seed. DPS and TotalEvents matched exactly. Mean/median wins: CI_ST_10 5.48/6.23%; Windwalker DungeonSlice 9.26/10.65%; Windwalker ST 12.48/12.21%; Shadow Priest ST 10.40/10.35%; Havoc DH 5T 8.91/9.47%; Dev Evoker 5T 9.05/10.32%. Build time on that toolchain was 36.9s baseline vs 59.8s IPO. The full CI DungeonSlice profile was invalid because Demon Hunter disables that fight style by default (engine/class_modules/sc_demon_hunter.cpp:11273), so Windwalker DungeonSlice was used as the substituted control. Patched CMake validation using SC_ENABLE_LTO=OFF vs default ON remained output-equivalent: CI_ST_10 mean/median wins 3.74/4.63%; Windwalker ST 11.45/10.85%. The existing MSVC C4244 warning at engine/class_modules/sc_druid.cpp:8909 was unchanged. --- CMakeLists.txt | 22 ++++++++++++++++++++++ engine/CMakeLists.txt | 1 + qt/CMakeLists.txt | 3 ++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8662ba4b15e..43c4daa7b06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ option(SC_NO_NETWORKING "Disable all networking related stuff." OFF) option(SC_USE_FLAT_INSTALL "Install files into a flat folder structure" ${WIN32}) option(SC_EVENT_QUEUE_DEBUG "Enable Event Queue Debug Info" OFF) +option(SC_ENABLE_LTO "Enable IPO/LTO for non-Debug builds" ON) set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") set(CMAKE_CXX_STANDARD_REQUIRED YES) @@ -53,6 +54,26 @@ function(sc_common_compiler_options target) ) endfunction() +if(SC_ENABLE_LTO) + include(CheckIPOSupported) + check_ipo_supported(RESULT SC_IPO_SUPPORTED OUTPUT SC_IPO_OUTPUT LANGUAGES CXX) + if(SC_IPO_SUPPORTED) + message(STATUS "IPO/LTO enabled for non-Debug builds") + else() + message(STATUS "IPO/LTO requested but not supported by this toolchain: ${SC_IPO_OUTPUT}") + endif() +endif() + +function(sc_enable_lto target) + if(SC_ENABLE_LTO AND SC_IPO_SUPPORTED) + set_target_properties(${target} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE ON + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON + INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL ON + ) + endif() +endfunction() + ### Git Hash ### # Get the current working branch @@ -80,6 +101,7 @@ endif() add_executable(simc engine/sc_main.cpp) target_link_libraries(simc engine) sc_common_compiler_options(simc) +sc_enable_lto(simc) install(TARGETS simc DESTINATION ${SIMC_INSTALL_BIN}) diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index f680840d5c9..a457aba3587 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -9,6 +9,7 @@ include(../source_files/cmake_engine.txt) add_library(engine ${source_files}) target_include_directories(engine PUBLIC . ./include ./lib) sc_common_compiler_options(engine) +sc_enable_lto(engine) # Make cmake selections visible to C++ code if(SC_NO_THREADING) diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index d2b11b18dd4..df068722b40 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -36,6 +36,7 @@ if (${QT_VERSION_MAJOR} EQUAL 6) endif() sc_common_compiler_options(SimulationCraft) +sc_enable_lto(SimulationCraft) target_include_directories(SimulationCraft PUBLIC ../engine/) target_link_libraries(SimulationCraft @@ -74,4 +75,4 @@ DESTINATION ${SIMC_INSTALL_SHARED}/locale) if(WIN32) include(${PROJECT_SOURCE_DIR}/cmake/windeployqt.cmake) windeployqt(SimulationCraft) -endif() \ No newline at end of file +endif()