@@ -350,6 +350,9 @@ top_level_options!(
350
350
// is currently just a hack and will be removed eventually, so please
351
351
// try to not rely on this too much.
352
352
actually_rustdoc: bool [ TRACKED ] ,
353
+
354
+ // Number of object files/codegen units to produce on the backend
355
+ codegen_units: usize [ UNTRACKED ] ,
353
356
}
354
357
) ;
355
358
@@ -512,6 +515,7 @@ pub fn basic_options() -> Options {
512
515
unstable_features : UnstableFeatures :: Disallow ,
513
516
debug_assertions : true ,
514
517
actually_rustdoc : false ,
518
+ codegen_units : 1 ,
515
519
}
516
520
}
517
521
@@ -529,11 +533,6 @@ impl Options {
529
533
( self . debugging_opts . query_dep_graph || self . debugging_opts . incremental_info )
530
534
}
531
535
532
- pub fn single_codegen_unit ( & self ) -> bool {
533
- self . incremental . is_none ( ) ||
534
- self . cg . codegen_units == 1
535
- }
536
-
537
536
pub fn file_path_mapping ( & self ) -> FilePathMapping {
538
537
FilePathMapping :: new (
539
538
self . debugging_opts . remap_path_prefix_from . iter ( ) . zip (
@@ -791,7 +790,7 @@ macro_rules! options {
791
790
fn parse_opt_uint( slot: & mut Option <usize >, v: Option <& str >) -> bool {
792
791
match v {
793
792
Some ( s) => { * slot = s. parse( ) . ok( ) ; slot. is_some( ) }
794
- None => { * slot = None ; true }
793
+ None => { * slot = None ; false }
795
794
}
796
795
}
797
796
@@ -924,7 +923,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
924
923
"metadata to mangle symbol names with" ) ,
925
924
extra_filename: String = ( "" . to_string( ) , parse_string, [ UNTRACKED ] ,
926
925
"extra data to put in each output filename" ) ,
927
- codegen_units: usize = ( 1 , parse_uint , [ UNTRACKED ] ,
926
+ codegen_units: Option < usize > = ( None , parse_opt_uint , [ UNTRACKED ] ,
928
927
"divide crate into N units to optimize in parallel" ) ,
929
928
remark: Passes = ( SomePasses ( Vec :: new( ) ) , parse_passes, [ UNTRACKED ] ,
930
929
"print remarks for these optimization passes (space separated, or \" all\" )" ) ,
@@ -1521,27 +1520,35 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
1521
1520
}
1522
1521
1523
1522
let mut cg = build_codegen_options ( matches, error_format) ;
1523
+ let mut codegen_units = cg. codegen_units ;
1524
1524
1525
1525
// Issue #30063: if user requests llvm-related output to one
1526
1526
// particular path, disable codegen-units.
1527
- if matches. opt_present ( "o" ) && cg. codegen_units != 1 {
1528
- let incompatible: Vec < _ > = output_types. iter ( )
1529
- . map ( |ot_path| ot_path. 0 )
1530
- . filter ( |ot| {
1531
- !ot. is_compatible_with_codegen_units_and_single_output_file ( )
1532
- } ) . collect ( ) ;
1533
- if !incompatible. is_empty ( ) {
1534
- for ot in & incompatible {
1535
- early_warn ( error_format, & format ! ( "--emit={} with -o incompatible with \
1536
- -C codegen-units=N for N > 1",
1537
- ot. shorthand( ) ) ) ;
1527
+ let incompatible: Vec < _ > = output_types. iter ( )
1528
+ . map ( |ot_path| ot_path. 0 )
1529
+ . filter ( |ot| {
1530
+ !ot. is_compatible_with_codegen_units_and_single_output_file ( )
1531
+ } )
1532
+ . map ( |ot| ot. shorthand ( ) )
1533
+ . collect ( ) ;
1534
+ if !incompatible. is_empty ( ) {
1535
+ match codegen_units {
1536
+ Some ( n) if n > 1 => {
1537
+ if matches. opt_present ( "o" ) {
1538
+ for ot in & incompatible {
1539
+ early_warn ( error_format, & format ! ( "--emit={} with -o incompatible with \
1540
+ -C codegen-units=N for N > 1",
1541
+ ot) ) ;
1542
+ }
1543
+ early_warn ( error_format, "resetting to default -C codegen-units=1" ) ;
1544
+ codegen_units = Some ( 1 ) ;
1545
+ }
1538
1546
}
1539
- early_warn ( error_format, "resetting to default -C codegen-units=1" ) ;
1540
- cg. codegen_units = 1 ;
1547
+ _ => codegen_units = Some ( 1 ) ,
1541
1548
}
1542
1549
}
1543
1550
1544
- if cg . codegen_units < 1 {
1551
+ if codegen_units == Some ( 0 ) {
1545
1552
early_error ( error_format, "Value for codegen units must be a positive nonzero integer" ) ;
1546
1553
}
1547
1554
@@ -1550,12 +1557,17 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
1550
1557
// case, but it would be confusing to have the validity of
1551
1558
// `-Z lto -C codegen-units=2` depend on details of the crate being
1552
1559
// compiled, so we complain regardless.
1553
- if cg. lto && cg. codegen_units > 1 {
1554
- // This case is impossible to handle because LTO expects to be able
1555
- // to combine the entire crate and all its dependencies into a
1556
- // single compilation unit, but each codegen unit is in a separate
1557
- // LLVM context, so they can't easily be combined.
1558
- early_error ( error_format, "can't perform LTO when using multiple codegen units" ) ;
1560
+ if cg. lto {
1561
+ if let Some ( n) = codegen_units {
1562
+ if n > 1 {
1563
+ // This case is impossible to handle because LTO expects to be able
1564
+ // to combine the entire crate and all its dependencies into a
1565
+ // single compilation unit, but each codegen unit is in a separate
1566
+ // LLVM context, so they can't easily be combined.
1567
+ early_error ( error_format, "can't perform LTO when using multiple codegen units" ) ;
1568
+ }
1569
+ }
1570
+ codegen_units = Some ( 1 ) ;
1559
1571
}
1560
1572
1561
1573
if cg. lto && debugging_opts. incremental . is_some ( ) {
@@ -1720,6 +1732,34 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
1720
1732
1721
1733
let incremental = debugging_opts. incremental . as_ref ( ) . map ( |m| PathBuf :: from ( m) ) ;
1722
1734
1735
+ let codegen_units = codegen_units. unwrap_or_else ( || {
1736
+ match opt_level {
1737
+ // If we're compiling at `-O0` then default to 32 codegen units.
1738
+ // The number here shouldn't matter too too much as debug mode
1739
+ // builds don't rely on performance at all, meaning that lost
1740
+ // opportunities for inlining through multiple codegen units is
1741
+ // a non-issue.
1742
+ //
1743
+ // Note that the high number here doesn't mean that we'll be
1744
+ // spawning a large number of threads in parallel. The backend
1745
+ // of rustc contains global rate limiting through the
1746
+ // `jobserver` crate so we'll never overload the system with too
1747
+ // much work, but rather we'll only be optimizing when we're
1748
+ // otherwise cooperating with other instances of rustc.
1749
+ //
1750
+ // Rather the high number here means that we should be able to
1751
+ // keep a lot of idle cpus busy. By ensuring that no codegen
1752
+ // unit takes *too* long to build we'll be guaranteed that all
1753
+ // cpus will finish pretty closely to one another and we should
1754
+ // make relatively optimal use of system resources
1755
+ OptLevel :: No => 32 ,
1756
+
1757
+ // All other optimization levels default use one codegen unit,
1758
+ // the historical default in Rust for a Long Time.
1759
+ _ => 1 ,
1760
+ }
1761
+ } ) ;
1762
+
1723
1763
( Options {
1724
1764
crate_types,
1725
1765
optimize : opt_level,
@@ -1744,6 +1784,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
1744
1784
unstable_features : UnstableFeatures :: from_environment ( ) ,
1745
1785
debug_assertions,
1746
1786
actually_rustdoc : false ,
1787
+ codegen_units,
1747
1788
} ,
1748
1789
cfg)
1749
1790
}
@@ -2447,7 +2488,7 @@ mod tests {
2447
2488
opts. cg . extra_filename = String :: from ( "extra-filename" ) ;
2448
2489
assert_eq ! ( reference. dep_tracking_hash( ) , opts. dep_tracking_hash( ) ) ;
2449
2490
2450
- opts. cg . codegen_units = 42 ;
2491
+ opts. cg . codegen_units = Some ( 42 ) ;
2451
2492
assert_eq ! ( reference. dep_tracking_hash( ) , opts. dep_tracking_hash( ) ) ;
2452
2493
2453
2494
opts. cg . remark = super :: SomePasses ( vec ! [ String :: from( "pass1" ) ,
0 commit comments