@@ -18,7 +18,9 @@ use std::process::Command;
18
18
19
19
use object:: read:: archive:: ArchiveFile ;
20
20
use object:: BinaryFormat ;
21
+ use sha2:: Digest ;
21
22
23
+ use crate :: bolt:: { instrument_with_bolt, optimize_with_bolt} ;
22
24
use crate :: builder:: { Builder , Kind , RunConfig , ShouldRun , Step } ;
23
25
use crate :: cache:: { Interned , INTERNER } ;
24
26
use crate :: channel;
@@ -1904,6 +1906,26 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
1904
1906
}
1905
1907
}
1906
1908
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
+
1907
1929
/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
1908
1930
///
1909
1931
/// Returns whether the files were actually copied.
@@ -1955,7 +1977,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
1955
1977
} else {
1956
1978
PathBuf :: from ( file)
1957
1979
} ;
1958
- builder . install ( & file, dst_libdir, 0o644 ) ;
1980
+ install_llvm_file ( builder , & file, dst_libdir) ;
1959
1981
}
1960
1982
!builder. config . dry_run ( )
1961
1983
} else {
@@ -1986,6 +2008,117 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
1986
2008
}
1987
2009
}
1988
2010
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
+
1989
2122
#[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
1990
2123
pub struct LlvmTools {
1991
2124
pub target : TargetSelection ,
0 commit comments