From 2054565e988c2845cc6e0198cc5cecf8887691ba Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Tue, 18 May 2021 16:08:42 -0700 Subject: [PATCH] [CMake] Don't LTO optimize targets that aren't part of any distribution When using distributions, targets that aren't included in any distribution don't need to be as optimized as targets that are included since those targets are typically only used for tests. We might consider avoiding LTO for these targets altogether, see https://lists.llvm.org/pipermail/llvm-dev/2021-April/149843.html Differential Revision: https://reviews.llvm.org/D102732 --- CMakeLists.txt | 3 +- cmake/modules/AddLLVM.cmake | 19 +++++- cmake/modules/LLVMDistributionSupport.cmake | 68 ++++++++++++++------- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5febba8043..135036f509d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -931,6 +931,8 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") include(AddLLVM) include(TableGen) +include(LLVMDistributionSupport) + if( MINGW AND NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # People report that -O3 is unreliable on MinGW. The traditional # build also uses -O2 for that reason: @@ -1119,7 +1121,6 @@ endif() # This must be at the end of the LLVM root CMakeLists file because it must run # after all targets are created. -include(LLVMDistributionSupport) llvm_distribution_add_targets() process_llvm_pass_plugins(GEN_CONFIG) diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake index f3b27937fd8..9c2b8537430 100644 --- a/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake @@ -218,13 +218,30 @@ if (NOT DEFINED LLVM_LINKER_DETECTED) endif() function(add_link_opts target_name) + get_llvm_distribution(${target_name} in_distribution in_distribution_var) + if(NOT in_distribution) + # Don't LTO optimize targets that aren't part of any distribution. + if (LLVM_ENABLE_LTO) + # We may consider avoiding LTO altogether by using -fembed-bitcode + # and teaching the linker to select machine code from .o files, see + # https://lists.llvm.org/pipermail/llvm-dev/2021-April/149843.html + if((UNIX OR MINGW) AND LLVM_USE_LINKER STREQUAL "lld") + set_property(TARGET ${target_name} APPEND_STRING PROPERTY + LINK_FLAGS " -Wl,--lto-O0") + elseif(LINKER_IS_LLD_LINK) + set_property(TARGET ${target_name} APPEND_STRING PROPERTY + LINK_FLAGS " /opt:lldlto=0") + endif() + endif() + endif() + # Don't use linker optimizations in debug builds since it slows down the # linker in a context where the optimizations are not important. if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") # Pass -O3 to the linker. This enabled different optimizations on different # linkers. - if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|SunOS|AIX|OS390" OR WIN32)) + if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|SunOS|AIX|OS390" OR WIN32) AND in_distribution) set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-O3") endif() diff --git a/cmake/modules/LLVMDistributionSupport.cmake b/cmake/modules/LLVMDistributionSupport.cmake index 72641012a91..e1c9a6cce5e 100644 --- a/cmake/modules/LLVMDistributionSupport.cmake +++ b/cmake/modules/LLVMDistributionSupport.cmake @@ -56,6 +56,46 @@ endfunction() # only defines other functions (i.e. it doesn't execute any more code directly). llvm_distribution_build_target_map() +# Look up the distribution a particular target belongs to. +# - target: The target to look up. +# - in_distribution_var: The variable with this name is set in the caller's +# scope to indicate if the target is in any distribution. If no distributions +# have been configured, this will always be set to true. +# - distribution_var: The variable with this name is set in the caller's scope +# to indicate the distribution name for the target. If the target belongs to +# the default (unnamed) distribution, or if no distributions have been +# configured, it's set to the empty string. +# - UMBRELLA: The (optional) umbrella target that the target is a part of. For +# example, all LLVM libraries have the umbrella target llvm-libraries. +function(get_llvm_distribution target in_distribution_var distribution_var) + if(NOT LLVM_DISTRIBUTION_COMPONENTS AND NOT LLVM_DISTRIBUTIONS) + set(${in_distribution_var} YES PARENT_SCOPE) + set(${distribution_var} "" PARENT_SCOPE) + return() + endif() + + cmake_parse_arguments(ARG "" UMBRELLA "" ${ARGN}) + get_property(distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) + if(ARG_UMBRELLA) + get_property(umbrella_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${ARG_UMBRELLA}) + if(distribution AND umbrella_distribution AND NOT distribution STREQUAL umbrella_distribution) + message(SEND_ERROR "Target ${target} has different distribution ${distribution} from its" + " umbrella target ${ARG_UMBRELLA} distribution ${umbrella_distribution}") + elseif(NOT distribution) + set(distribution ${umbrella_distribution}) + endif() + endif() + if(distribution) + set(${in_distribution_var} YES PARENT_SCOPE) + if(distribution STREQUAL "") + set(distribution "") + endif() + set(${distribution_var} "${distribution}" PARENT_SCOPE) + else() + set(${in_distribution_var} NO PARENT_SCOPE) + endif() +endfunction() + # Get the EXPORT argument to use for an install command for a target in a # project. As explained at the top of the file, the project export set for a # distribution is named ${project}{distribution}Targets (except for LLVM where @@ -79,31 +119,15 @@ function(get_target_export_arg target project export_arg_var) set(suffix "Targets") endif() - if(NOT LLVM_DISTRIBUTION_COMPONENTS AND NOT LLVM_DISTRIBUTIONS) - set(${export_arg_var} EXPORT ${project}${suffix} PARENT_SCOPE) - set_property(GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS True) - return() - endif() + get_llvm_distribution(${target} in_distribution distribution ${ARGN}) - cmake_parse_arguments(ARG "" UMBRELLA "" ${ARGN}) - get_property(distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) - if(ARG_UMBRELLA) - get_property(umbrella_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${ARG_UMBRELLA}) - if(distribution AND umbrella_distribution AND NOT distribution STREQUAL umbrella_distribution) - message(SEND_ERROR "Target ${target} has different distribution ${distribution} from its" - " umbrella target ${ARG_UMBRELLA} distribution ${umbrella_distribution}") - elseif(NOT distribution) - set(distribution ${umbrella_distribution}) - endif() - endif() - if(distribution) - if(distribution STREQUAL "") - set(${export_arg_var} EXPORT ${project}${suffix} PARENT_SCOPE) - set_property(GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS True) - else() - set(${export_arg_var} EXPORT ${project}${distribution}${suffix} PARENT_SCOPE) + if(in_distribution) + set(${export_arg_var} EXPORT ${project}${distribution}${suffix} PARENT_SCOPE) + if(distribution) string(TOUPPER "${distribution}" distribution_upper) set_property(GLOBAL PROPERTY ${project_upper}_${distribution_upper}_HAS_EXPORTS True) + else() + set_property(GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS True) endif() else() set(${export_arg_var} "" PARENT_SCOPE)