Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions cmake/Modules/OpmCompile.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# - Compile main library target

include(OpmInterproceduralOptimization)

option (STRIP_DEBUGGING_SYMBOLS "use separate files for the executable code and the debugging symbols" OFF)

macro (opm_compile opm)
Expand Down Expand Up @@ -43,8 +45,11 @@ macro (opm_compile opm)
SOVERSION ${${opm}_VERSION}
VERSION ${${opm}_VERSION}
LINK_FLAGS "${${opm}_LINKER_FLAGS_STR}"
POSITION_INDEPENDENT_CODE TRUE
POSITION_INDEPENDENT_CODE TRUE
)

opm_interprocedural_optimization(TARGET ${${opm}_TARGET})

if (${${opm}_LIBRARY_TYPE} STREQUAL "SHARED")
# libs that will be linked with the main lib
string(REGEX REPLACE "([;^])[^;]+\\.a[;$]" "\\1" _public_libs
Expand All @@ -70,7 +75,7 @@ macro (opm_compile opm)
# unset this variable to signal that no library is generated
set (${opm}_TARGET)
endif (${opm}_SOURCES)

# pre-compile common headers; this is setup *after* the library to pick
# up extra options set there
if (PRECOMPILE_HEADERS)
Expand Down Expand Up @@ -99,5 +104,5 @@ macro (opm_compile opm)
if (${opm}_TARGET)
set(${opm}_LIBRARY $<TARGET_FILE:${${opm}_TARGET}>)
endif (${opm}_TARGET)

endmacro (opm_compile opm)
161 changes: 161 additions & 0 deletions cmake/Modules/OpmInterproceduralOptimization.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
include(CheckIPOSupported)
include(TestCXXAcceptsFlag)

# ------------------------------------------------------------------------------
# opm_interprocedural_optimization
#
# Configure interprocedural optimization (IPO) for a target.
#
# This function enables IPO (Link Time Optimization) on the specified target.
# It supports the standard CMake IPO interface as well as extended interfaces for
# GCC and Clang settings.
#
# The type of optimization applied is controlled via the cache variable:
# OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE
# which can be one of:
# - CMake: use standard CMake IPO via INTERPROCEDURAL_OPTIMIZATION_<config>
# - Clang: use Clang's ThinLTO with parallelism and cache configuration
# - GNU: use GNU's incremental LTO with parallelism and cache configuration
# - NONE: disable IPO
#
# Incremental cache directories are automatically managed under:
# ${CMAKE_BINARY_DIR}/LTOCache/<config>
#
# Usage:
#
# opm_interprocedural_optimization(
# TARGET <target>
# [CONFIGURATION_TYPES <config1;config2;...>]
# )
#
# Arguments:
# TARGET (required) Target to which optimization will be applied.
# CONFIGURATION_TYPES (optional) List of configuration names (e.g. Release).
# If omitted, the default list from:
# OPM_INTERPROCEDURAL_OPTIMIZATION_CONFIGURATION_TYPES
# is used.
#
# Cache Variables:
# OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE (CMake, GNU, Clang, NONE)
# OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS (e.g. 1, 8)
# OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY (e.g. "prune_after=604800")
# OPM_INTERPROCEDURAL_OPTIMIZATION_CONFIGURATION_TYPES (e.g. "Release;RelWithDebInfo")
#
# ------------------------------------------------------------------------------

set(OPM_INTERPROCEDURAL_OPTIMIZATION_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "Default configuration types to apply OPM interprocedural optimization.")
set(OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS 1 CACHE STRING "Default OPM interprocedural optimization jobs.")
set(OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY "" CACHE STRING "Default OPM interprocedural optimization cache policy.")
mark_as_advanced(OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS)
mark_as_advanced(OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY)

# define possible values for LTO (order matters: first one in the list is used as default type)
set(opm_ipo_types)
check_ipo_supported(LANGUAGES C CXX RESULT ipo_supported)
if(ipo_supported)
list(PREPEND opm_ipo_types CMake)
endif()

# Add custom for known compiler versions
if(ipo_supported)
if((CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0))
list(PREPEND opm_ipo_types Clang)
elseif((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5.4))
list(PREPEND opm_ipo_types GNU)
endif()
endif()

# Some linkers decide to discard "unused" functions prematurely and takes long, so disable for now.
list(INSERT opm_ipo_types 0 NONE)

set(OPM_INTERPROCEDURAL_OPTIMIZATION_TYPES ${opm_ipo_types} CACHE STRING "OPM interprocedural optimization types." FORCE)
mark_as_advanced(OPM_INTERPROCEDURAL_OPTIMIZATION_TYPES)
list(GET OPM_INTERPROCEDURAL_OPTIMIZATION_TYPES 0 opm_ipo_default_type)

list(JOIN OPM_INTERPROCEDURAL_OPTIMIZATION_TYPES ", " opm_ipo_types_str)
set(OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE ${opm_ipo_default_type} CACHE STRING "Default OPM interprocedural optimization type. Possible values: ${opm_ipo_types_str}")
set_property(CACHE OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE PROPERTY STRINGS ${OPM_INTERPROCEDURAL_OPTIMIZATION_TYPES})

message(STATUS "OPM interprocedural optimization type: ${OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE}")

function(opm_interprocedural_optimization)
cmake_parse_arguments(OPM_IPO "" "TARGET" "CONFIGURATION_TYPES" ${ARGN})

# if not set, use the default configuration types
if(NOT OPM_IPO_CONFIGURATION_TYPES)
set(OPM_IPO_CONFIGURATION_TYPES ${OPM_INTERPROCEDURAL_OPTIMIZATION_CONFIGURATION_TYPES})
endif()

foreach(config ${OPM_IPO_CONFIGURATION_TYPES})
if((CMAKE_CONFIGURATION_TYPES MATCHES ${config}) OR (CMAKE_BUILD_TYPE MATCHES ${config}))

set(LTO_CACHE_PATH ${CMAKE_BINARY_DIR}/LTOCache/${config})

if(OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE STREQUAL CMake)
# Use default CMake IPO
string(TOUPPER ${config} uconfig)
set_target_properties(${OPM_IPO_TARGET} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_${uconfig} ON)
elseif(OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE STREQUAL GNU)
if((NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6.4) AND (NOT OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS EQUAL 1))
# https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Optimize-Options.html
target_compile_options(${OPM_IPO_TARGET} PRIVATE $<$<CONFIG:${config}>:-flto=${OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS}>)
target_link_options(${OPM_IPO_TARGET} INTERFACE $<$<CONFIG:${config}>:-flto=${OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS}>)
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5.4)
# https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Optimize-Options.html
target_compile_options(${OPM_IPO_TARGET} PRIVATE $<$<CONFIG:${config}>:-flto>)
target_link_options(${OPM_IPO_TARGET} INTERFACE $<$<CONFIG:${config}>:-flto>)
endif()

if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0)
# use incremental LTO https://gcc.gnu.org/onlinedocs/gcc-15.2.0/gcc/Optimize-Options.html
target_compile_options(${OPM_IPO_TARGET} PRIVATE $<$<CONFIG:${config}>:-flto-incremental=${LTO_CACHE_PATH}>)
target_link_options(${OPM_IPO_TARGET} INTERFACE $<$<CONFIG:${config}>:-flto-incremental=${LTO_CACHE_PATH}>)

# Configure cache directory
file(MAKE_DIRECTORY ${LTO_CACHE_PATH})
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${LTO_CACHE_PATH})
endif()

elseif(OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE STREQUAL Clang)
# Use ThinLTO and reuse cache (see https://releases.llvm.org/20.1.0/tools/clang/docs/ThinLTO.html)

target_compile_options(${OPM_IPO_TARGET} PRIVATE $<$<CONFIG:${config}>:-flto=thin>)
target_link_options(${OPM_IPO_TARGET} INTERFACE $<$<CONFIG:${config}>:-flto=thin>)

# Configure cache directory
file(MAKE_DIRECTORY ${LTO_CACHE_PATH})
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${LTO_CACHE_PATH})

# Parallel and cache options are linker dependent
if(${CMAKE_CXX_COMPILER_LINKER_ID} MATCHES "LLD")
Comment thread
SoilRos marked this conversation as resolved.
target_link_options(${OPM_IPO_TARGET} INTERFACE
$<$<CONFIG:${config}>:LINKER:--thinlto-jobs=${OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS}>
$<$<CONFIG:${config}>:LINKER:--thinlto-cache-dir=${LTO_CACHE_PATH}>
)
if(OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY)
target_link_options(${OPM_IPO_TARGET} INTERFACE
$<$<CONFIG:${config}>:LINKER:--thinlto-cache-policy=${OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY}>
)
endif()
elseif(${CMAKE_CXX_COMPILER_LINKER_ID} MATCHES "GNU|GNUgold|MOLD")
target_link_options(${OPM_IPO_TARGET} INTERFACE
$<$<CONFIG:${config}>:LINKER:-plugin-opt,jobs=${OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS}>
$<$<CONFIG:${config}>:LINKER:-plugin-opt,cache-dir=${LTO_CACHE_PATH}>
)
if(OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY)
target_link_options(${OPM_IPO_TARGET} INTERFACE
$<$<CONFIG:${config}>:LINKER:-plugin-opt,cache-policy=${OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY}>
)
endif()
elseif(${CMAKE_CXX_COMPILER_LINKER_ID} MATCHES "AppleClang")
target_link_options(${OPM_IPO_TARGET} INTERFACE
$<$<CONFIG:${config}>:LINKER:-mllvm,-threads=${OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS}>
$<$<CONFIG:${config}>:LINKER:-cache_path_lto,${LTO_CACHE_PATH}>
)
else()
message(DEBUG "IPO for Clang is supported, but linker type '${CMAKE_CXX_COMPILER_LINKER_ID}' is unrecognized. Skip adding parallelism or cache flags.")
endif()
endif()
endif()
endforeach()
endfunction()
28 changes: 0 additions & 28 deletions cmake/Modules/UseOptimization.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,6 @@ if (CXX_COMPAT_GCC)
# extra flags passed for optimization
set (_opt_flags "")

# link-time (a.k.a. global) optimizations
# disabled due to widespread bugs in the linker plugin
option (WHOLE_PROG_OPTIM "Whole program optimization (lto)" OFF)
if (WHOLE_PROG_OPTIM)
check_cxx_accepts_flag ("-flto" HAVE_LINK_OPTS)
check_cxx_accepts_flag ("-fuse-linker-plugin" HAVE_LINK_PLUGIN)
if (HAVE_LINK_OPTS)
list (APPEND _opt_flags "-flto")
endif (HAVE_LINK_OPTS)
if (HAVE_LINK_PLUGIN)
list (APPEND _opt_flags "-fuse-linker-plugin")
endif (HAVE_LINK_PLUGIN)
if(HAVE_LINK_OPTS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
string(REPLACE "." ";" VERSION_LIST "${CMAKE_C_COMPILER_VERSION}")
list(GET VERSION_LIST 0 VER_MAJOR)
find_program(LTO_AR_COMMAND NAMES ${CMAKE_C_COMPILER}-ar gcc-ar-${VER_MAJOR} gcc-ar)
find_program(LTO_RANLIB_COMMAND NAMES ${CMAKE_C_COMPILER}-ranlib gcc-ranlib-${VER_MAJOR} gcc-ranlib)
if(LTO_AR_COMMAND)
set(CMAKE_AR ${LTO_AR_COMMAND})
message(STATUS "Using LTO-enabled ar: ${CMAKE_AR}")
endif()
if(LTO_RANLIB_COMMAND)
set(CMAKE_RANLIB ${LTO_RANLIB_COMMAND})
message(STATUS "Using LTO-enabled ranlib: ${CMAKE_RANLIB}")
endif()
endif()
endif (WHOLE_PROG_OPTIM)

# native instruction set tuning
option (WITH_NATIVE "Use native instruction set" ON)
if (WITH_NATIVE)
Expand Down
84 changes: 74 additions & 10 deletions cmake/OPM-CMake.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ to do the necessary modifications.

2. Add the name of the translation unit to the `PROGRAM_SOURCE_FILES` list
in `CMakeLists_files.txt`.

### Creating a New Module

1. Copy the directory `cmake/` and all sub-directories from opm-core. This
Expand Down Expand Up @@ -213,15 +213,79 @@ a good idea if you are building the library on the same machine
as you will be using the library. Default is ON.

<tr>
<td> WHOLE_PROG_OPTIM
<td>
Perform an extra round of optimization when linking the program.
(Usually the compiler only optimizes within the translation unit).
If your compiler supports this, it usually leads to a faster runtime.
Default is OFF.
<td> OPM_INTERPROCEDURAL_OPTIMIZATION_TYPE
<td>
Controls the type of interprocedural optimization (IPO, also known as
Link Time Optimization or LTO) applied when linking targets. If
enabled and supported by your compiler, IPO can significantly improve
runtime performance by optimizing across translation units.<br>
Possible values are:
<ul>
<li><b>CMake</b>: Use the standard CMake IPO interface
(<code>INTERPROCEDURAL_OPTIMIZATION</code> property). This is
supported by most modern compilers.</li>
<li><b>Clang</b>: Use Clang's ThinLTO, enabling parallelism and
cache configuration for faster and more scalable builds. This mode
is selected automatically for Clang 7.0+ if available.</li>
<li><b>GNU</b>: Use GNU (GCC) incremental LTO with parallelism and
cache configuration. This mode is selected for GCC 4.5+ if available.
</li>
<li><b>NONE</b>: Disable interprocedural optimization.</li>
</ul>
The default is <code>NONE</code>.<br>
</td>
</tr>

<tr>
<td> OPM_INTERPROCEDURAL_OPTIMIZATION_CONFIGURATION_TYPES
<td>
A semicolon-separated list of build configurations for which
interprocedural optimization is enabled (e.g.,
<code>Release;RelWithDebInfo</code>). If not set, the default is
<code>Release;RelWithDebInfo</code>.<br>
This controls which CMake build types (such as Release or RelWithDebInfo)
will have IPO/LTO enabled. You can override this to enable or disable
IPO for custom configurations.
</td>
</tr>

<tr>
<td> OPM_INTERPROCEDURAL_OPTIMIZATION_JOBS
<td>
Controls the degree of parallelism for IPO/LTO linking and optimization.
The effect depends on the selected IPO type and compiler:
<ul>
<li>For <b>Clang</b> ThinLTO, sets the number of parallel jobs for
the ThinLTO backend (passed to the linker as <code>--thinlto-jobs
</code> or equivalent).</li>
<li>For <b>GNU</b> (GCC), sets the number of parallel LTO jobs (passed
as <code>-flto=N</code>).</li>
</ul>
If set to <code>0</code>, the build system or linker may attempt to use
all available cores, which can be too aggressive if the build is already
parallelized (e.g., with <code>make -j</code> or Ninja).<br>
The default is <code>1</code>.
</td>
</tr>

<tr>
<td> OPM_INTERPROCEDURAL_OPTIMIZATION_CACHE_POLICY
<td>
Specifies the cache policy for IPO/LTO cache directories, if supported
by the selected compiler and linker. For example, with Clang ThinLTO
and the LLD linker, you can set <code>prune_after=604800</code> to prune
cache files older than one week. This value is passed to the linker if
supported, allowing you to control cache size and cleanup behavior.<br>
The default is empty (no explicit policy).<br>
Cache directories are automatically created under
<code>${CMAKE_BINARY_DIR}/LTOCache/&lt;config&gt;</code> for each
configuration.
</td>
</tr>


</table>

## Modules Reference

### Project-specific Files
Expand Down Expand Up @@ -391,7 +455,7 @@ must always be done from the beginning in order to link correctly.
<td>
Write .la file which will make libtool find our library. This enables
users of our library to use libtool even if we did not do so ourselves.

</table>

### Build System Modules
Expand Down Expand Up @@ -717,7 +781,7 @@ translation.
<td>
Textual concatenation of all components of the version number (see below)
with a dot inbetween. This form of version number can be compared using
CMake VERSION_{LESS|EQUAL|GREATER} operators.
CMake VERSION_{LESS|EQUAL|GREATER} operators.

<tr>
<td> _VERSION_MAJOR
Expand Down