@@ -18,7 +18,9 @@ use std::process::Command;
1818
1919use object:: read:: archive:: ArchiveFile ;
2020use object:: BinaryFormat ;
21+ use sha2:: Digest ;
2122
23+ use crate :: bolt:: { instrument_with_bolt, optimize_with_bolt} ;
2224use crate :: builder:: { Builder , Kind , RunConfig , ShouldRun , Step } ;
2325use crate :: cache:: { Interned , INTERNER } ;
2426use crate :: channel;
@@ -1904,6 +1906,26 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
19041906 }
19051907}
19061908
1909+ fn install_llvm_file ( builder : & Builder < ' _ > , source : & Path , destination : & Path ) {
1910+ if builder. config . dry_run ( ) {
1911+ return ;
1912+ }
1913+
1914+ // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
1915+ // This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
1916+ // We perform the instrumentation/optimization here, on the fly, just before they are being
1917+ // packaged into some destination directory.
1918+ let postprocessed = if builder. config . llvm_bolt_profile_generate {
1919+ builder. ensure ( BoltInstrument :: new ( source. to_path_buf ( ) ) )
1920+ } else if let Some ( path) = & builder. config . llvm_bolt_profile_use {
1921+ builder. ensure ( BoltOptimize :: new ( source. to_path_buf ( ) , path. into ( ) ) )
1922+ } else {
1923+ source. to_path_buf ( )
1924+ } ;
1925+
1926+ builder. install ( & postprocessed, destination, 0o644 ) ;
1927+ }
1928+
19071929/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
19081930///
19091931/// Returns whether the files were actually copied.
@@ -1955,7 +1977,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
19551977 } else {
19561978 PathBuf :: from ( file)
19571979 } ;
1958- builder . install ( & file, dst_libdir, 0o644 ) ;
1980+ install_llvm_file ( builder , & file, dst_libdir) ;
19591981 }
19601982 !builder. config . dry_run ( )
19611983 } else {
@@ -1986,6 +2008,117 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
19862008 }
19872009}
19882010
2011+ /// Creates an output path to a BOLT-manipulated artifact for the given `file`.
2012+ /// The hash of the file is used to make sure that we don't mix BOLT artifacts amongst different
2013+ /// files with the same name.
2014+ ///
2015+ /// We need to keep the file-name the same though, to make sure that copying the manipulated file
2016+ /// to a directory will not change the final file path.
2017+ fn create_bolt_output_path ( builder : & Builder < ' _ > , file : & Path , hash : & str ) -> PathBuf {
2018+ let directory = builder. out . join ( "bolt" ) . join ( hash) ;
2019+ t ! ( fs:: create_dir_all( & directory) ) ;
2020+ directory. join ( file. file_name ( ) . unwrap ( ) )
2021+ }
2022+
2023+ /// Instrument the provided file with BOLT.
2024+ /// Returns a path to the instrumented artifact.
2025+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
2026+ pub struct BoltInstrument {
2027+ file : PathBuf ,
2028+ hash : String ,
2029+ }
2030+
2031+ impl BoltInstrument {
2032+ fn new ( file : PathBuf ) -> Self {
2033+ let mut hasher = sha2:: Sha256 :: new ( ) ;
2034+ hasher. update ( t ! ( fs:: read( & file) ) ) ;
2035+ let hash = hex:: encode ( hasher. finalize ( ) . as_slice ( ) ) ;
2036+
2037+ Self { file, hash }
2038+ }
2039+ }
2040+
2041+ impl Step for BoltInstrument {
2042+ type Output = PathBuf ;
2043+
2044+ const ONLY_HOSTS : bool = false ;
2045+ const DEFAULT : bool = false ;
2046+
2047+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
2048+ run. never ( )
2049+ }
2050+
2051+ fn run ( self , builder : & Builder < ' _ > ) -> PathBuf {
2052+ if builder. build . config . dry_run ( ) {
2053+ return self . file . clone ( ) ;
2054+ }
2055+
2056+ if builder. build . config . llvm_from_ci {
2057+ println ! ( "warning: trying to use BOLT with LLVM from CI, this will probably not work" ) ;
2058+ }
2059+
2060+ println ! ( "Instrumenting {} with BOLT" , self . file. display( ) ) ;
2061+
2062+ let output_path = create_bolt_output_path ( builder, & self . file , & self . hash ) ;
2063+ if !output_path. is_file ( ) {
2064+ instrument_with_bolt ( & self . file , & output_path) ;
2065+ }
2066+ output_path
2067+ }
2068+ }
2069+
2070+ /// Optimize the provided file with BOLT.
2071+ /// Returns a path to the optimized artifact.
2072+ ///
2073+ /// The hash is stored in the step to make sure that we don't optimize the same file
2074+ /// twice (even under different file paths).
2075+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
2076+ pub struct BoltOptimize {
2077+ file : PathBuf ,
2078+ profile : PathBuf ,
2079+ hash : String ,
2080+ }
2081+
2082+ impl BoltOptimize {
2083+ fn new ( file : PathBuf , profile : PathBuf ) -> Self {
2084+ let mut hasher = sha2:: Sha256 :: new ( ) ;
2085+ hasher. update ( t ! ( fs:: read( & file) ) ) ;
2086+ hasher. update ( t ! ( fs:: read( & profile) ) ) ;
2087+ let hash = hex:: encode ( hasher. finalize ( ) . as_slice ( ) ) ;
2088+
2089+ Self { file, profile, hash }
2090+ }
2091+ }
2092+
2093+ impl Step for BoltOptimize {
2094+ type Output = PathBuf ;
2095+
2096+ const ONLY_HOSTS : bool = false ;
2097+ const DEFAULT : bool = false ;
2098+
2099+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
2100+ run. never ( )
2101+ }
2102+
2103+ fn run ( self , builder : & Builder < ' _ > ) -> PathBuf {
2104+ if builder. build . config . dry_run ( ) {
2105+ return self . file . clone ( ) ;
2106+ }
2107+
2108+ if builder. build . config . llvm_from_ci {
2109+ println ! ( "warning: trying to use BOLT with LLVM from CI, this will probably not work" ) ;
2110+ }
2111+
2112+ println ! ( "Optimizing {} with BOLT" , self . file. display( ) ) ;
2113+
2114+ let output_path = create_bolt_output_path ( builder, & self . file , & self . hash ) ;
2115+ if !output_path. is_file ( ) {
2116+ optimize_with_bolt ( & self . file , & self . profile , & output_path) ;
2117+ }
2118+ output_path
2119+ }
2120+ }
2121+
19892122#[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
19902123pub struct LlvmTools {
19912124 pub target : TargetSelection ,
0 commit comments