@@ -2,9 +2,11 @@ use std::any::Any;
2
2
use std:: ffi:: CString ;
3
3
use std:: os:: raw:: { c_char, c_int} ;
4
4
5
+ use rustc:: dep_graph:: { WorkProduct , WorkProductFileKind , WorkProductId } ;
5
6
use rustc:: middle:: cstore:: EncodedMetadata ;
6
- use rustc:: mir:: mono:: { Linkage as RLinkage , Visibility } ;
7
+ use rustc:: mir:: mono:: { CodegenUnit , Linkage as RLinkage , Visibility } ;
7
8
use rustc:: session:: config:: { DebugInfo , OutputType } ;
9
+ use rustc_session:: cgu_reuse_tracker:: CguReuse ;
8
10
use rustc_codegen_ssa:: back:: linker:: LinkerInfo ;
9
11
use rustc_codegen_ssa:: CrateInfo ;
10
12
@@ -172,20 +174,32 @@ fn run_aot(
172
174
tcx : TyCtxt < ' _ > ,
173
175
metadata : EncodedMetadata ,
174
176
need_metadata_module : bool ,
175
- ) -> Box < CodegenResults > {
176
- let new_module = |name : String | {
177
+ ) -> Box < ( CodegenResults , FxHashMap < WorkProductId , WorkProduct > ) > {
178
+ let mut work_products = FxHashMap :: default ( ) ;
179
+
180
+ fn new_module ( tcx : TyCtxt < ' _ > , name : String ) -> Module < crate :: backend:: Backend > {
177
181
let module = crate :: backend:: make_module ( tcx. sess , name) ;
178
182
assert_eq ! ( pointer_ty( tcx) , module. target_config( ) . pointer_type( ) ) ;
179
183
module
180
184
} ;
181
185
186
+ struct ModuleCodegenResult ( CompiledModule , Option < ( WorkProductId , WorkProduct ) > ) ;
187
+
188
+ use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
189
+
190
+ impl < HCX > HashStable < HCX > for ModuleCodegenResult {
191
+ fn hash_stable ( & self , _: & mut HCX , _: & mut StableHasher ) {
192
+ // do nothing
193
+ }
194
+ }
195
+
182
196
fn emit_module < B : Backend > (
183
197
tcx : TyCtxt < ' _ > ,
184
198
name : String ,
185
199
kind : ModuleKind ,
186
200
mut module : Module < B > ,
187
201
debug : Option < DebugContext > ,
188
- ) -> CompiledModule
202
+ ) -> ModuleCodegenResult
189
203
where B :: Product : Emit + WriteDebugInfo ,
190
204
{
191
205
module. finalize_definitions ( ) ;
@@ -200,54 +214,146 @@ fn run_aot(
200
214
. temp_path ( OutputType :: Object , Some ( & name) ) ;
201
215
let obj = product. emit ( ) ;
202
216
std:: fs:: write ( & tmp_file, obj) . unwrap ( ) ;
203
- CompiledModule {
204
- name,
205
- kind,
206
- object : Some ( tmp_file) ,
207
- bytecode : None ,
208
- bytecode_compressed : None ,
209
- }
217
+
218
+ let work_product = if std:: env:: var ( "CG_CLIF_INCR_CACHE" ) . is_ok ( ) {
219
+ rustc_incremental:: copy_cgu_workproducts_to_incr_comp_cache_dir (
220
+ tcx. sess ,
221
+ & name,
222
+ & [ ( WorkProductFileKind :: Object , tmp_file. clone ( ) ) ] ,
223
+ )
224
+ } else {
225
+ None
226
+ } ;
227
+
228
+ ModuleCodegenResult (
229
+ CompiledModule {
230
+ name,
231
+ kind,
232
+ object : Some ( tmp_file) ,
233
+ bytecode : None ,
234
+ bytecode_compressed : None ,
235
+ } ,
236
+ work_product,
237
+ )
210
238
} ;
211
239
212
240
let ( _, cgus) = tcx. collect_and_partition_mono_items ( LOCAL_CRATE ) ;
213
241
214
- let modules = time ( tcx. sess , "codegen mono items" , move || {
242
+ if tcx. dep_graph . is_fully_enabled ( ) {
243
+ for cgu in & * cgus {
244
+ tcx. codegen_unit ( cgu. name ( ) ) ;
245
+ }
246
+ }
247
+
248
+ let modules = time ( tcx. sess , "codegen mono items" , || {
215
249
cgus. iter ( ) . map ( |cgu| {
216
- let mono_items = cgu. items_in_deterministic_order ( tcx) ;
250
+ let cgu_reuse = determine_cgu_reuse ( tcx, cgu) ;
251
+ tcx. sess . cgu_reuse_tracker . set_actual_reuse ( & cgu. name ( ) . as_str ( ) , cgu_reuse) ;
252
+
253
+ match cgu_reuse {
254
+ CguReuse :: No => { }
255
+ CguReuse :: PreLto => {
256
+ let incr_comp_session_dir = tcx. sess . incr_comp_session_dir ( ) ;
257
+ let mut object = None ;
258
+ let work_product = cgu. work_product ( tcx) ;
259
+ for ( kind, saved_file) in & work_product. saved_files {
260
+ let obj_out = match kind {
261
+ WorkProductFileKind :: Object => {
262
+ let path = tcx. output_filenames ( LOCAL_CRATE ) . temp_path ( OutputType :: Object , Some ( & cgu. name ( ) . as_str ( ) ) ) ;
263
+ object = Some ( path. clone ( ) ) ;
264
+ path
265
+ }
266
+ WorkProductFileKind :: Bytecode | WorkProductFileKind :: BytecodeCompressed => {
267
+ panic ! ( "cg_clif doesn't use bytecode" ) ;
268
+ }
269
+ } ;
270
+ let source_file = rustc_incremental:: in_incr_comp_dir ( & incr_comp_session_dir, & saved_file) ;
271
+ if let Err ( err) = rustc_fs_util:: link_or_copy ( & source_file, & obj_out) {
272
+ tcx. sess . err ( & format ! (
273
+ "unable to copy {} to {}: {}" ,
274
+ source_file. display( ) ,
275
+ obj_out. display( ) ,
276
+ err
277
+ ) ) ;
278
+ }
279
+ }
280
+
281
+ work_products. insert ( cgu. work_product_id ( ) , work_product) ;
217
282
218
- let mut module = new_module ( cgu. name ( ) . as_str ( ) . to_string ( ) ) ;
283
+ return CompiledModule {
284
+ name : cgu. name ( ) . to_string ( ) ,
285
+ kind : ModuleKind :: Regular ,
286
+ object,
287
+ bytecode : None ,
288
+ bytecode_compressed : None ,
289
+ } ;
290
+ }
291
+ CguReuse :: PostLto => unreachable ! ( ) ,
292
+ }
293
+
294
+ let dep_node = cgu. codegen_dep_node ( tcx) ;
295
+ let ( ModuleCodegenResult ( module, work_product) , _) =
296
+ tcx. dep_graph . with_task ( dep_node, tcx, cgu. name ( ) , module_codegen, rustc:: dep_graph:: hash_result) ;
219
297
220
- let mut debug = if tcx. sess . opts . debuginfo != DebugInfo :: None {
221
- let debug = DebugContext :: new (
298
+ fn module_codegen ( tcx : TyCtxt < ' _ > , cgu_name : rustc_span:: Symbol ) -> ModuleCodegenResult {
299
+ let cgu = tcx. codegen_unit ( cgu_name) ;
300
+ let mono_items = cgu. items_in_deterministic_order ( tcx) ;
301
+
302
+ let mut module = new_module ( tcx, cgu_name. as_str ( ) . to_string ( ) ) ;
303
+
304
+ let mut debug = if tcx. sess . opts . debuginfo != DebugInfo :: None {
305
+ let debug = DebugContext :: new (
306
+ tcx,
307
+ module. target_config ( ) . pointer_type ( ) . bytes ( ) as u8 ,
308
+ ) ;
309
+ Some ( debug)
310
+ } else {
311
+ None
312
+ } ;
313
+
314
+ codegen_mono_items ( tcx, & mut module, debug. as_mut ( ) , mono_items) ;
315
+ crate :: main_shim:: maybe_create_entry_wrapper ( tcx, & mut module) ;
316
+
317
+ emit_module (
222
318
tcx,
223
- module . target_config ( ) . pointer_type ( ) . bytes ( ) as u8 ,
224
- ) ;
225
- Some ( debug )
226
- } else {
227
- None
228
- } ;
319
+ cgu . name ( ) . as_str ( ) . to_string ( ) ,
320
+ ModuleKind :: Regular ,
321
+ module ,
322
+ debug ,
323
+ )
324
+ }
229
325
230
- codegen_mono_items ( tcx, & mut module, debug. as_mut ( ) , mono_items) ;
231
- crate :: main_shim:: maybe_create_entry_wrapper ( tcx, & mut module) ;
326
+ if let Some ( ( id, product) ) = work_product {
327
+ work_products. insert ( id, product) ;
328
+ }
232
329
233
- emit_module (
234
- tcx,
235
- cgu. name ( ) . as_str ( ) . to_string ( ) ,
236
- ModuleKind :: Regular ,
237
- module,
238
- debug,
239
- )
330
+ module
240
331
} ) . collect :: < Vec < _ > > ( )
241
332
} ) ;
242
333
243
334
tcx. sess . abort_if_errors ( ) ;
244
335
245
- let mut allocator_module = new_module ( "allocator_shim" . to_string ( ) ) ;
336
+ let mut allocator_module = new_module ( tcx , "allocator_shim" . to_string ( ) ) ;
246
337
let created_alloc_shim = crate :: allocator:: codegen ( tcx, & mut allocator_module) ;
247
338
339
+ let allocator_module = if created_alloc_shim {
340
+ let ModuleCodegenResult ( module, work_product) = emit_module (
341
+ tcx,
342
+ "allocator_shim" . to_string ( ) ,
343
+ ModuleKind :: Allocator ,
344
+ allocator_module,
345
+ None ,
346
+ ) ;
347
+ if let Some ( ( id, product) ) = work_product {
348
+ work_products. insert ( id, product) ;
349
+ }
350
+ Some ( module)
351
+ } else {
352
+ None
353
+ } ;
354
+
248
355
rustc_incremental:: assert_dep_graph ( tcx) ;
249
356
rustc_incremental:: save_dep_graph ( tcx) ;
250
- rustc_incremental:: finalize_session_directory ( tcx. sess , tcx. crate_hash ( LOCAL_CRATE ) ) ;
251
357
252
358
let metadata_module = if need_metadata_module {
253
359
let _timer = tcx. prof . generic_activity ( "codegen crate metadata" ) ;
@@ -284,27 +390,17 @@ fn run_aot(
284
390
None
285
391
} ;
286
392
287
- Box :: new ( CodegenResults {
393
+ Box :: new ( ( CodegenResults {
288
394
crate_name : tcx. crate_name ( LOCAL_CRATE ) ,
289
395
modules,
290
- allocator_module : if created_alloc_shim {
291
- Some ( emit_module (
292
- tcx,
293
- "allocator_shim" . to_string ( ) ,
294
- ModuleKind :: Allocator ,
295
- allocator_module,
296
- None ,
297
- ) )
298
- } else {
299
- None
300
- } ,
396
+ allocator_module,
301
397
metadata_module,
302
398
crate_hash : tcx. crate_hash ( LOCAL_CRATE ) ,
303
399
metadata,
304
400
windows_subsystem : None , // Windows is not yet supported
305
401
linker_info : LinkerInfo :: new ( tcx) ,
306
402
crate_info : CrateInfo :: new ( tcx) ,
307
- } )
403
+ } , work_products ) )
308
404
}
309
405
310
406
fn codegen_mono_items < ' tcx > (
@@ -402,3 +498,36 @@ fn time<R>(sess: &Session, name: &'static str, f: impl FnOnce() -> R) -> R {
402
498
println ! ( "[{}] end time: {:?}" , name, after - before) ;
403
499
res
404
500
}
501
+
502
+ // Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953
503
+ fn determine_cgu_reuse < ' tcx > ( tcx : TyCtxt < ' tcx > , cgu : & CodegenUnit < ' tcx > ) -> CguReuse {
504
+ if !tcx. dep_graph . is_fully_enabled ( ) {
505
+ return CguReuse :: No ;
506
+ }
507
+
508
+ let work_product_id = & cgu. work_product_id ( ) ;
509
+ if tcx. dep_graph . previous_work_product ( work_product_id) . is_none ( ) {
510
+ // We don't have anything cached for this CGU. This can happen
511
+ // if the CGU did not exist in the previous session.
512
+ return CguReuse :: No ;
513
+ }
514
+
515
+ // Try to mark the CGU as green. If it we can do so, it means that nothing
516
+ // affecting the LLVM module has changed and we can re-use a cached version.
517
+ // If we compile with any kind of LTO, this means we can re-use the bitcode
518
+ // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
519
+ // know that later). If we are not doing LTO, there is only one optimized
520
+ // version of each module, so we re-use that.
521
+ let dep_node = cgu. codegen_dep_node ( tcx) ;
522
+ assert ! (
523
+ !tcx. dep_graph. dep_node_exists( & dep_node) ,
524
+ "CompileCodegenUnit dep-node for CGU `{}` already exists before marking." ,
525
+ cgu. name( )
526
+ ) ;
527
+
528
+ if tcx. dep_graph . try_mark_green ( tcx, & dep_node) . is_some ( ) {
529
+ CguReuse :: PreLto
530
+ } else {
531
+ CguReuse :: No
532
+ }
533
+ }
0 commit comments