NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
16.77k stars 13.18k forks source link

LLVM Bolt #176536

Open npatsakula opened 2 years ago

npatsakula commented 2 years ago

This project should be part of the llvmPackage_14.bintools-unwrapped, but it's missing.

BOLT is a post-link optimizer developed to speed up large applications.

It achieves the improvements by optimizing application's code layout based on execution profile gathered by sampling profiler, such as Linux perf tool. An overview of the ideas implemented in BOLT along with a discussion of its potential and current results is available in CGO'19 paper.

Metadata

pca006132 commented 5 months ago

OK I managed to build this on NixOS, but with tons of patches. I think the upstream bolt is not ready for separate compilation yet, so I need to copy a bunch of stuff from elsewhere, but here is the build:

{ stdenv
, llvm_meta
, monorepoSrc
, runCommand
, cmake
, python3
, libxml2
, libllvm
, libclang
, version
}:

stdenv.mkDerivation rec {
  pname = "bolt";
  inherit version;

  # Blank llvm dir just so relative path works
  src = runCommand "llvm-src-${version}" { } ''
    mkdir $out
    cp -r ${monorepoSrc}/cmake "$out"
    cp -r ${monorepoSrc}/${pname} "$out"
    cp -r ${monorepoSrc}/third-party "$out"

    # tablegen stuff, probably not the best way but it works...
    cp -r ${monorepoSrc}/llvm/ "$out"
  '';

  sourceRoot = "${src.name}/bolt";

  patches = [ ./tons-of-stuff.patch ];

  nativeBuildInputs = [ cmake python3 ];
  buildInputs = [ libllvm libclang libxml2 ];

  outputs = [ "out" "lib" ];

  meta = llvm_meta // {
    homepage = "https://github.com/llvm/llvm-project/tree/main/bolt";
    description = "LLVM post-link optimizer (unwrpped).";
  };
}

the patch:

```diff diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ff90c1f7..0a4996e39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,15 @@ -include(ExternalProject) +cmake_minimum_required(VERSION 3.20.0) + +if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) + set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) +endif() +include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake + NO_POLICY_SCOPE) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(bolt) + set(BOLT_BUILT_STANDALONE TRUE) +endif() set(BOLT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(BOLT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) @@ -7,9 +18,207 @@ set(CMAKE_CXX_STANDARD 17) # Add path for custom modules. list(INSERT CMAKE_MODULE_PATH 0 "${BOLT_SOURCE_DIR}/cmake/modules") +if(BOLT_BUILT_STANDALONE) + set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") + set(CMAKE_CXX_STANDARD_REQUIRED YES) + set(CMAKE_CXX_EXTENSIONS NO) + + if(NOT MSVC_IDE) + set(LLVM_ENABLE_ASSERTIONS ${ENABLE_ASSERTIONS} + CACHE BOOL "Enable assertions") + # Assertions should follow llvm-config's. + mark_as_advanced(LLVM_ENABLE_ASSERTIONS) + endif() + + find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") + + # Turn into CACHE PATHs for overwritting + + # We can't check LLVM_CONFIG here, because find_package(LLVM ...) also sets + # LLVM_CONFIG. + if (NOT LLVM_CONFIG_FOUND) + # Pull values from LLVMConfig.cmake. We can drop this once the llvm-config + # path is removed. + set(INCLUDE_DIRS ${LLVM_INCLUDE_DIRS}) + set(LLVM_OBJ_DIR "${LLVM_BINARY_DIR}") + # N.B. this is just a default value, the CACHE PATHs below can be overridden. + set(MAIN_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../llvm") + else() + set(INCLUDE_DIRS "${LLVM_BINARY_DIR}/include" "${MAIN_INCLUDE_DIR}") + endif() + + set(LLVM_INCLUDE_DIRS ${INCLUDE_DIRS} CACHE PATH "Path to llvm/include and any other header dirs needed") + set(LLVM_BINARY_DIR "${LLVM_OBJ_ROOT}" CACHE PATH "Path to LLVM build tree") + set(LLVM_MAIN_SRC_DIR "${MAIN_SRC_DIR}" CACHE PATH "Path to LLVM source tree") + + set(LLVM_TOOLS_BINARY_DIR "${LLVM_TOOLS_BINARY_DIR}" CACHE PATH "Path to llvm/bin") + set(LLVM_LIBRARY_DIR "${LLVM_LIBRARY_DIR}" CACHE PATH "Path to llvm/lib") + + find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} + NO_DEFAULT_PATH) + + # They are used as destination of target generators. + set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) + set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) + if(WIN32 OR CYGWIN) + # DLL platform -- put DLLs into bin. + set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) + else() + set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) + endif() + + option(LLVM_INSTALL_TOOLCHAIN_ONLY + "Only include toolchain files in the 'install' target." OFF) + + option(LLVM_FORCE_USE_OLD_TOOLCHAIN + "Set to ON to force using an old, unsupported host toolchain." OFF) + option(CLANG_ENABLE_BOOTSTRAP "Generate the clang bootstrap target" OFF) + option(LLVM_ENABLE_LIBXML2 "Use libxml2 if available." ON) + + include(AddLLVM) + include(TableGen) + include(HandleLLVMOptions) + include(VersionFromVCS) + include(CheckAtomic) + include(GetErrcMessages) + include(LLVMDistributionSupport) + + if (NOT DEFINED LLVM_INCLUDE_TESTS) + set(LLVM_INCLUDE_TESTS ON) + endif() + + include_directories(${LLVM_INCLUDE_DIRS}) + link_directories("${LLVM_LIBRARY_DIR}") + + set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) + set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} ) + set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} ) + + find_package(Python3 ${LLVM_MINIMUM_PYTHON_VERSION} REQUIRED + COMPONENTS Interpreter) + + if(LLVM_INCLUDE_TESTS) + # Check prebuilt llvm/utils. + if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX} + AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/count${CMAKE_EXECUTABLE_SUFFIX} + AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX}) + set(LLVM_UTILS_PROVIDED ON) + endif() + + # Seek installed Lit. + find_program(LLVM_LIT + NAMES llvm-lit lit.py lit + PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit" + DOC "Path to lit.py") + + if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) + # Note: path not really used, except for checking if lit was found + if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit utils/llvm-lit) + endif() + if(NOT LLVM_UTILS_PROVIDED) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/count utils/count) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not) + set(LLVM_UTILS_PROVIDED ON) + set(CLANG_TEST_DEPS FileCheck count not) + endif() + endif() + + if(LLVM_LIT) + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LIT_ARGS_DEFAULT "-sv") + if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") + endif() + set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") + + get_errc_messages(LLVM_LIT_ERRC_MESSAGES) + + # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. + if( WIN32 AND NOT CYGWIN ) + set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") + endif() + else() + set(LLVM_INCLUDE_TESTS OFF) + endif() + + umbrella_lit_testsuite_begin(check-all) + endif() # LLVM_INCLUDE_TESTS + + # tablegen stuff, copied from llvm/lib/Target/*/CMakeLists.txt + set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_SRC_DIR}/lib/Target/X86/X86.td) + list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target/X86) + tablegen(LLVM include/X86GenAsmMatcher.inc -gen-asm-matcher) + tablegen(LLVM include/X86GenAsmWriter.inc -gen-asm-writer) + tablegen(LLVM include/X86GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1) + tablegen(LLVM include/X86GenCallingConv.inc -gen-callingconv) + tablegen(LLVM include/X86GenDAGISel.inc -gen-dag-isel) + tablegen(LLVM include/X86GenDisassemblerTables.inc -gen-disassembler) + tablegen(LLVM include/X86GenEVEX2VEXTables.inc -gen-x86-EVEX2VEX-tables) + tablegen(LLVM include/X86GenExegesis.inc -gen-exegesis) + tablegen(LLVM include/X86GenFastISel.inc -gen-fast-isel) + tablegen(LLVM include/X86GenGlobalISel.inc -gen-global-isel) + tablegen(LLVM include/X86GenInstrInfo.inc -gen-instr-info + -instr-info-expand-mi-operand-info=0) + tablegen(LLVM include/X86GenMnemonicTables.inc -gen-x86-mnemonic-tables -asmwriternum=1) + tablegen(LLVM include/X86GenRegisterBank.inc -gen-register-bank) + tablegen(LLVM include/X86GenRegisterInfo.inc -gen-register-info) + tablegen(LLVM include/X86GenSubtargetInfo.inc -gen-subtarget) + tablegen(LLVM include/X86GenFoldTables.inc -gen-x86-fold-tables -asmwriternum=1) + add_public_tablegen_target(X86CommonTableGen) + + set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_SRC_DIR}/lib/Target/AArch64/AArch64.td) + list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target/AArch64) + tablegen(LLVM include/AArch64GenAsmMatcher.inc -gen-asm-matcher) + tablegen(LLVM include/AArch64GenAsmWriter.inc -gen-asm-writer) + tablegen(LLVM include/AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1) + tablegen(LLVM include/AArch64GenCallingConv.inc -gen-callingconv) + tablegen(LLVM include/AArch64GenDAGISel.inc -gen-dag-isel) + tablegen(LLVM include/AArch64GenDisassemblerTables.inc -gen-disassembler) + tablegen(LLVM include/AArch64GenFastISel.inc -gen-fast-isel) + tablegen(LLVM include/AArch64GenGlobalISel.inc -gen-global-isel) + tablegen(LLVM include/AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner-matchtable + -combiners="AArch64O0PreLegalizerCombiner") + tablegen(LLVM include/AArch64GenPreLegalizeGICombiner.inc -gen-global-isel-combiner-matchtable + -combiners="AArch64PreLegalizerCombiner") + tablegen(LLVM include/AArch64GenPostLegalizeGICombiner.inc -gen-global-isel-combiner-matchtable + -combiners="AArch64PostLegalizerCombiner") + tablegen(LLVM include/AArch64GenPostLegalizeGILowering.inc -gen-global-isel-combiner-matchtable + -combiners="AArch64PostLegalizerLowering") + tablegen(LLVM include/AArch64GenInstrInfo.inc -gen-instr-info) + tablegen(LLVM include/AArch64GenMCCodeEmitter.inc -gen-emitter) + tablegen(LLVM include/AArch64GenMCPseudoLowering.inc -gen-pseudo-lowering) + tablegen(LLVM include/AArch64GenRegisterBank.inc -gen-register-bank) + tablegen(LLVM include/AArch64GenRegisterInfo.inc -gen-register-info) + tablegen(LLVM include/AArch64GenSubtargetInfo.inc -gen-subtarget) + tablegen(LLVM include/AArch64GenSystemOperands.inc -gen-searchable-tables) + tablegen(LLVM include/AArch64GenExegesis.inc -gen-exegesis) + add_public_tablegen_target(AArch64CommonTableGen) + + set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV/RISCV.td) + list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV) + tablegen(LLVM include/RISCVGenAsmMatcher.inc -gen-asm-matcher) + tablegen(LLVM include/RISCVGenAsmWriter.inc -gen-asm-writer) + tablegen(LLVM include/RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter) + tablegen(LLVM include/RISCVGenDAGISel.inc -gen-dag-isel) + tablegen(LLVM include/RISCVGenDisassemblerTables.inc -gen-disassembler) + tablegen(LLVM include/RISCVGenGlobalISel.inc -gen-global-isel) + tablegen(LLVM include/RISCVGenInstrInfo.inc -gen-instr-info) + tablegen(LLVM include/RISCVGenMCCodeEmitter.inc -gen-emitter) + tablegen(LLVM include/RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering) + tablegen(LLVM include/RISCVGenRegisterBank.inc -gen-register-bank) + tablegen(LLVM include/RISCVGenRegisterInfo.inc -gen-register-info) + tablegen(LLVM include/RISCVGenSearchableTables.inc -gen-searchable-tables) + tablegen(LLVM include/RISCVGenSubtargetInfo.inc -gen-subtarget) + add_public_tablegen_target(RISCVCommonTableGen) +endif() # standalone + # Determine default set of targets to build -- the intersection of # those BOLT supports and those LLVM is targeting. -set(BOLT_TARGETS_TO_BUILD_all "AArch64;X86;RISCV") +set(BOLT_TARGETS_TO_BUILD_all "AArch64;X86") # RISCV build fails for now set(BOLT_TARGETS_TO_BUILD_default) foreach (tgt ${BOLT_TARGETS_TO_BUILD_all}) if (tgt IN_LIST LLVM_TARGETS_TO_BUILD) @@ -91,6 +300,8 @@ if (BOLT_ENABLE_RUNTIME) if(CMAKE_SYSROOT) list(APPEND extra_args -DCMAKE_SYSROOT=${CMAKE_SYSROOT}) endif() + + include(ExternalProject) ExternalProject_Add(bolt_rt SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/runtime" STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/bolt_rt-stamps diff --git a/lib/Utils/CMakeLists.txt b/lib/Utils/CMakeLists.txt index d14033142..86af77e16 100644 --- a/lib/Utils/CMakeLists.txt +++ b/lib/Utils/CMakeLists.txt @@ -1,3 +1,4 @@ +get_source_info(${CMAKE_CURRENT_SOURCE_DIR} revision repository) add_llvm_library(LLVMBOLTUtils CommandLineOpts.cpp Utils.cpp @@ -7,9 +8,7 @@ add_llvm_library(LLVMBOLTUtils LINK_LIBS ${LLVM_PTHREAD_LIB} - DEPENDS - llvm_vcsrevision_h - LINK_COMPONENTS Support ) +target_compile_definitions(LLVMBOLTUtils PRIVATE LLVM_REVISION=${revision}) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 8472ce00b..441f174be 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -15,12 +15,10 @@ add_library(bolt_rt_instr STATIC instr.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.h ) -set_target_properties(bolt_rt_instr PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_DIR}") add_library(bolt_rt_hugify STATIC hugify.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.h ) -set_target_properties(bolt_rt_hugify PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_DIR}") set(BOLT_RT_FLAGS -ffreestanding @@ -36,18 +34,23 @@ target_include_directories(bolt_rt_instr PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_compile_options(bolt_rt_hugify PRIVATE ${BOLT_RT_FLAGS}) target_include_directories(bolt_rt_hugify PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -install(TARGETS bolt_rt_instr DESTINATION "lib${LLVM_LIBDIR_SUFFIX}") -install(TARGETS bolt_rt_hugify DESTINATION "lib${LLVM_LIBDIR_SUFFIX}") +install(TARGETS bolt_rt_instr + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") +install(TARGETS bolt_rt_hugify + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") if (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang.*") add_library(bolt_rt_instr_osx STATIC instr.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.h ) - set_target_properties(bolt_rt_instr_osx PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_DIR}") target_include_directories(bolt_rt_instr_osx PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_compile_options(bolt_rt_instr_osx PRIVATE -target x86_64-apple-darwin19.6.0 ${BOLT_RT_FLAGS}) - install(TARGETS bolt_rt_instr_osx DESTINATION "lib${LLVM_LIBDIR_SUFFIX}") + install(TARGETS bolt_rt_instr_osx + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") endif() ```

The patch is really ugly and there are some things that are specific to NixOS (I integrated the gnu-install-dirs.patch in other llvm packages). Not sure if we want to try to get the changes upstreamed before opening a PR.

The build is successful, but I haven't yet tested it. Patching this is quite painful and consumed me 4 hours already...

pca006132 commented 5 months ago

it seems that it works directly without the need for wrapping.

RossComputerGuy commented 5 days ago

The upstream patch which makes packaging bolt possible in Nix has been merged. We'll have things here merged in not too long from now.