@@ -48,18 +48,11 @@ pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
48
48
}
49
49
}
50
50
51
- /// Performs LTO, which in the case of full LTO means merging all modules into
52
- /// a single one and returning it for further optimizing. For ThinLTO, it will
53
- /// do the global analysis necessary and return two lists, one of the modules
54
- /// the need optimization and another for modules that can simply be copied over
55
- /// from the incr. comp. cache.
56
- pub ( crate ) fn run ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
57
- modules : Vec < ModuleCodegen < ModuleLlvm > > ,
58
- cached_modules : Vec < ( SerializedModule < ModuleBuffer > , WorkProduct ) > ,
59
- timeline : & mut Timeline )
60
- -> Result < ( Vec < LtoModuleCodegen < LlvmCodegenBackend > > , Vec < WorkProduct > ) , FatalError >
51
+ fn prepare_lto ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
52
+ timeline : & mut Timeline ,
53
+ diag_handler : & Handler )
54
+ -> Result < ( Vec < CString > , Vec < ( SerializedModule < ModuleBuffer > , CString ) > ) , FatalError >
61
55
{
62
- let diag_handler = cgcx. create_diag_handler ( ) ;
63
56
let export_threshold = match cgcx. lto {
64
57
// We're just doing LTO for our one crate
65
58
Lto :: ThinLocal => SymbolExportLevel :: Rust ,
@@ -144,36 +137,74 @@ pub(crate) fn run(cgcx: &CodegenContext<LlvmCodegenBackend>,
144
137
}
145
138
}
146
139
140
+ Ok ( ( symbol_white_list, upstream_modules) )
141
+ }
142
+
143
+ /// Performs fat LTO by merging all modules into a single one and returning it
144
+ /// for further optimization.
145
+ pub ( crate ) fn run_fat ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
146
+ modules : Vec < ModuleCodegen < ModuleLlvm > > ,
147
+ timeline : & mut Timeline )
148
+ -> Result < LtoModuleCodegen < LlvmCodegenBackend > , FatalError >
149
+ {
150
+ let diag_handler = cgcx. create_diag_handler ( ) ;
151
+ let ( symbol_white_list, upstream_modules) = prepare_lto ( cgcx, timeline, & diag_handler) ?;
147
152
let symbol_white_list = symbol_white_list. iter ( )
148
153
. map ( |c| c. as_ptr ( ) )
149
154
. collect :: < Vec < _ > > ( ) ;
150
- match cgcx. lto {
151
- Lto :: Fat => {
152
- assert ! ( cached_modules. is_empty( ) ) ;
153
- let opt_jobs = fat_lto ( cgcx,
154
- & diag_handler,
155
- modules,
156
- upstream_modules,
157
- & symbol_white_list,
158
- timeline) ;
159
- opt_jobs. map ( |opt_jobs| ( opt_jobs, vec ! [ ] ) )
160
- }
161
- Lto :: Thin |
162
- Lto :: ThinLocal => {
163
- if cgcx. opts . debugging_opts . cross_lang_lto . enabled ( ) {
164
- unreachable ! ( "We should never reach this case if the LTO step \
165
- is deferred to the linker") ;
166
- }
167
- thin_lto ( cgcx,
168
- & diag_handler,
169
- modules,
170
- upstream_modules,
171
- cached_modules,
172
- & symbol_white_list,
173
- timeline)
155
+ fat_lto ( cgcx, & diag_handler, modules, upstream_modules, & symbol_white_list, timeline)
156
+ }
157
+
158
+ /// Performs thin LTO by performing necessary global analysis and returning two
159
+ /// lists, one of the modules that need optimization and another for modules that
160
+ /// can simply be copied over from the incr. comp. cache.
161
+ pub ( crate ) fn run_thin ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
162
+ modules : Vec < ( String , ThinBuffer ) > ,
163
+ cached_modules : Vec < ( SerializedModule < ModuleBuffer > , WorkProduct ) > ,
164
+ timeline : & mut Timeline )
165
+ -> Result < ( Vec < LtoModuleCodegen < LlvmCodegenBackend > > , Vec < WorkProduct > ) , FatalError >
166
+ {
167
+ let diag_handler = cgcx. create_diag_handler ( ) ;
168
+ let ( symbol_white_list, upstream_modules) = prepare_lto ( cgcx, timeline, & diag_handler) ?;
169
+ let symbol_white_list = symbol_white_list. iter ( )
170
+ . map ( |c| c. as_ptr ( ) )
171
+ . collect :: < Vec < _ > > ( ) ;
172
+ if cgcx. opts . debugging_opts . cross_lang_lto . enabled ( ) {
173
+ unreachable ! ( "We should never reach this case if the LTO step \
174
+ is deferred to the linker") ;
175
+ }
176
+ thin_lto ( cgcx,
177
+ & diag_handler,
178
+ modules,
179
+ upstream_modules,
180
+ cached_modules,
181
+ & symbol_white_list,
182
+ timeline)
183
+ }
184
+
185
+ pub ( crate ) fn prepare_thin (
186
+ cgcx : & CodegenContext < LlvmCodegenBackend > ,
187
+ module : ModuleCodegen < ModuleLlvm >
188
+ ) -> ( String , ThinBuffer ) {
189
+ let name = module. name . clone ( ) ;
190
+ let buffer = ThinBuffer :: new ( module. module_llvm . llmod ( ) ) ;
191
+
192
+ // We emit the module after having serialized it into a ThinBuffer
193
+ // because only then it will contain the ThinLTO module summary.
194
+ if let Some ( ref incr_comp_session_dir) = cgcx. incr_comp_session_dir {
195
+ if cgcx. config ( module. kind ) . emit_pre_thin_lto_bc {
196
+ let path = incr_comp_session_dir
197
+ . join ( pre_lto_bitcode_filename ( & name) ) ;
198
+
199
+ fs:: write ( & path, buffer. data ( ) ) . unwrap_or_else ( |e| {
200
+ panic ! ( "Error writing pre-lto-bitcode file `{}`: {}" ,
201
+ path. display( ) ,
202
+ e) ;
203
+ } ) ;
174
204
}
175
- Lto :: No => unreachable ! ( ) ,
176
205
}
206
+
207
+ ( name, buffer)
177
208
}
178
209
179
210
fn fat_lto ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
@@ -182,7 +213,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
182
213
mut serialized_modules : Vec < ( SerializedModule < ModuleBuffer > , CString ) > ,
183
214
symbol_white_list : & [ * const libc:: c_char ] ,
184
215
timeline : & mut Timeline )
185
- -> Result < Vec < LtoModuleCodegen < LlvmCodegenBackend > > , FatalError >
216
+ -> Result < LtoModuleCodegen < LlvmCodegenBackend > , FatalError >
186
217
{
187
218
info ! ( "going for a fat lto" ) ;
188
219
@@ -271,10 +302,10 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
271
302
timeline. record ( "passes" ) ;
272
303
}
273
304
274
- Ok ( vec ! [ LtoModuleCodegen :: Fat {
305
+ Ok ( LtoModuleCodegen :: Fat {
275
306
module : Some ( module) ,
276
307
_serialized_bitcode : serialized_bitcode,
277
- } ] )
308
+ } )
278
309
}
279
310
280
311
struct Linker < ' a > ( & ' a mut llvm:: Linker < ' a > ) ;
@@ -335,7 +366,7 @@ impl Drop for Linker<'a> {
335
366
/// they all go out of scope.
336
367
fn thin_lto ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
337
368
diag_handler : & Handler ,
338
- modules : Vec < ModuleCodegen < ModuleLlvm > > ,
369
+ modules : Vec < ( String , ThinBuffer ) > ,
339
370
serialized_modules : Vec < ( SerializedModule < ModuleBuffer > , CString ) > ,
340
371
cached_modules : Vec < ( SerializedModule < ModuleBuffer > , WorkProduct ) > ,
341
372
symbol_white_list : & [ * const libc:: c_char ] ,
@@ -355,41 +386,17 @@ fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
355
386
let mut module_names = Vec :: with_capacity ( full_scope_len) ;
356
387
let mut thin_modules = Vec :: with_capacity ( full_scope_len) ;
357
388
358
- // FIXME: right now, like with fat LTO, we serialize all in-memory
359
- // modules before working with them and ThinLTO. We really
360
- // shouldn't do this, however, and instead figure out how to
361
- // extract a summary from an in-memory module and then merge that
362
- // into the global index. It turns out that this loop is by far
363
- // the most expensive portion of this small bit of global
364
- // analysis!
365
- for ( i, module) in modules. into_iter ( ) . enumerate ( ) {
366
- info ! ( "local module: {} - {}" , i, module. name) ;
367
- let name = CString :: new ( module. name . clone ( ) ) . unwrap ( ) ;
368
- let buffer = ThinBuffer :: new ( module. module_llvm . llmod ( ) ) ;
369
-
370
- // We emit the module after having serialized it into a ThinBuffer
371
- // because only then it will contain the ThinLTO module summary.
372
- if let Some ( ref incr_comp_session_dir) = cgcx. incr_comp_session_dir {
373
- if cgcx. config ( module. kind ) . emit_pre_thin_lto_bc {
374
- let path = incr_comp_session_dir
375
- . join ( pre_lto_bitcode_filename ( & module. name ) ) ;
376
-
377
- fs:: write ( & path, buffer. data ( ) ) . unwrap_or_else ( |e| {
378
- panic ! ( "Error writing pre-lto-bitcode file `{}`: {}" ,
379
- path. display( ) ,
380
- e) ;
381
- } ) ;
382
- }
383
- }
384
-
389
+ for ( i, ( name, buffer) ) in modules. into_iter ( ) . enumerate ( ) {
390
+ info ! ( "local module: {} - {}" , i, name) ;
391
+ let cname = CString :: new ( name. clone ( ) ) . unwrap ( ) ;
385
392
thin_modules. push ( llvm:: ThinLTOModule {
386
- identifier : name . as_ptr ( ) ,
393
+ identifier : cname . as_ptr ( ) ,
387
394
data : buffer. data ( ) . as_ptr ( ) ,
388
395
len : buffer. data ( ) . len ( ) ,
389
396
} ) ;
390
397
thin_buffers. push ( buffer) ;
391
- module_names. push ( name ) ;
392
- timeline. record ( & module . name ) ;
398
+ module_names. push ( cname ) ;
399
+ timeline. record ( & name) ;
393
400
}
394
401
395
402
// FIXME: All upstream crates are deserialized internally in the
0 commit comments