Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LLVM Bolt #176536

Closed
npatsakula opened this issue Jun 6, 2022 · 3 comments · Fixed by #326240
Closed

LLVM Bolt #176536

npatsakula opened this issue Jun 6, 2022 · 3 comments · Fixed by #326240
Labels
0.kind: packaging request Request for a new package to be added

Comments

@npatsakula
Copy link
Contributor

npatsakula commented Jun 6, 2022

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

@npatsakula npatsakula added the 0.kind: packaging request Request for a new package to be added label Jun 6, 2022
@pca006132
Copy link
Contributor

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 --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
Copy link
Contributor

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

@RossComputerGuy
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.kind: packaging request Request for a new package to be added
Projects
None yet
3 participants