Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LTO with LLVM and CMake

I am trying to apply Link Time Optimization with LLVM on a CMake Project, that creates a shared library. My question is pretty much the same as this one:

Switching between GCC and Clang/LLVM using CMake.

However, the answers do not seem to be applicable anymore, since llvm-ld is not present in the new versions. On the command line, I run the following commands to get LTO (Assuming there are only 2 .cpp files):

Compile to byte code:

clang++ -c FirstClass.cpp -O3 -flto -o FirstClass.bc
clang++ -c SecondClass.cpp -O3 -flto -o SecondClass.bc

Link byte code:

llvm-link FirstClass.bc SecondClass.bc -o unoptimized.bc

Optimize byte code:

opt -O3 unoptimized.bc -o optimized.bc

Convert byte code to shared object:

clang++ -shared optimized.bc -o libTest.so

Could somebody please tell me how to have CMake run the additional steps?

like image 354
SPMP Avatar asked Mar 10 '16 17:03

SPMP


People also ask

What is LTO LLVM?

LLVM features powerful intermodular optimizations which can be used at link time. Link Time Optimization (LTO) is another name for intermodular optimization when performed during the link stage. This document describes the interface and design between the LTO optimizer and the linker.

Is GCC compatible with LLVM?

Yes, for C code Clang and GCC are compatible (they both use the GNU Toolchain for linking, in fact.)

Is LLVM better than GCC?

While LLVM and GCC both support a wide variety languages and libraries, they are licensed and developed differently. LLVM libraries are licensed more liberally and GCC has more restrictions for its reuse. When it comes to performance differences, GCC has been considered superior in the past.

What is full LTO?

LTO (Link Time Optimization) achieves better runtime performance through whole-program analysis and cross-module optimization. However, monolithic LTO implements this by merging all input into a single module, which is not scalable in time or memory, and also prevents fast incremental compiles.


3 Answers

The correct way to use Clang and enable LTO is using the -flto flag to the clang command line both at compile and link time.

In addition, you will need to be working on a platform with a linker that either directly supports LTO (Apple's platforms generally) or that have an LLVM linker plugin (Linux using the Gold linker, but I think some have gotten the BFD linker to support the linker plugin as well). If you're using the linker plugin, you'll need to make sure your install of LLVM built and installed the plugin. If it did, Clang will automatically add the necessary linker command line options to use the plugin when linking with -flto, even for shared objects.

Also, The LLVM project is working on a new linker (LLD) which will support LTO out of the box on all the platforms it supports, but it is still pretty early days. Currently I know of folks testing out its LTO support on Windows and Linux, and it seems to be working well but still misses many features.

like image 191
Chandler Carruth Avatar answered Oct 17 '22 01:10

Chandler Carruth


check_ipo_supported() resulted for me in "Policy CMP0069 is not set" error on CMake 3.9.1.

Per its help, CMake up to 3.8 only supported Intel compiler's LTO. It didn't work on XCode 9's clang for me either.

What worked, in the end:

cmake_policy(SET CMP0069 NEW)
include(CheckIPOSupported)
check_ipo_supported()

add_executable(Foobar SOURCES)
set_target_properties(Foobar PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)

Looks like add_executable() needs to be after cmake_policy(SET CMP0069 NEW).

LTO cache

target_link_libraries(Foobar "-Wl,-cache_path_lto,${PROJECT_BINARY_DIR}/lto.cache") did no harm.

Pick your command-line option depending on your linker.

More brutal option

According to @ChandlerCarruth's answer:

if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
    target_link_libraries(Foobar -flto)
endif ()
like image 3
Victor Sergienko Avatar answered Oct 17 '22 00:10

Victor Sergienko


Enabling (thin) lto on Cmake 3.9 and newer should be straightforward:

include(CheckIPOSupported)
check_ipo_supported()
set_target_properties(myProject PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)

Instead of set_target_properties per project, a single global setting of set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) can be done.

In order to speed up recompiles, a cache for LTO can be set:

function(append value)
    foreach(variable ${ARGN})
        set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
    endforeach(variable)
endfunction()

append("-fuse-ld=gold -Wl,--no-threads,--plugin-opt,cache-dir=${PROJECT_BINARY_DIR}/lto.cache" CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS)

This forces gold as linker, in order to use the right command line options. It might require a symlink of /usr/lib/LLVMgold.so to /usr/lib/llvm-4.0/lib/LLVMgold.so.

like image 2
Mr. White Avatar answered Oct 16 '22 23:10

Mr. White