[CMake] Don't LTO optimize targets that aren't part of any distribution
authorPetr Hosek <phosek@google.com>
Tue, 18 May 2021 23:08:42 +0000 (16:08 -0700)
committerPetr Hosek <phosek@google.com>
Wed, 19 May 2021 22:02:11 +0000 (15:02 -0700)
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

llvm/CMakeLists.txt
llvm/cmake/modules/AddLLVM.cmake
llvm/cmake/modules/LLVMDistributionSupport.cmake

index e5febba..135036f 100644 (file)
@@ -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)
 
index f3b2793..9c2b853 100644 (file)
@@ -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()
index 7264101..e1c9a6c 100644 (file)
@@ -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 "<DEFAULT>")
+      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 "<DEFAULT>")
-      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)