@@ -350,6 +350,9 @@ top_level_options!(
350350 // is currently just a hack and will be removed eventually, so please
351351 // try to not rely on this too much.
352352 actually_rustdoc: bool [ TRACKED ] ,
353+
354+ // Number of object files/codegen units to produce on the backend
355+ codegen_units: usize [ UNTRACKED ] ,
353356 }
354357) ;
355358
@@ -512,6 +515,7 @@ pub fn basic_options() -> Options {
512515 unstable_features : UnstableFeatures :: Disallow ,
513516 debug_assertions : true ,
514517 actually_rustdoc : false ,
518+ codegen_units : 1 ,
515519 }
516520}
517521
@@ -529,11 +533,6 @@ impl Options {
529533 ( self . debugging_opts . query_dep_graph || self . debugging_opts . incremental_info )
530534 }
531535
532- pub fn single_codegen_unit ( & self ) -> bool {
533- self . incremental . is_none ( ) ||
534- self . cg . codegen_units == 1
535- }
536-
537536 pub fn file_path_mapping ( & self ) -> FilePathMapping {
538537 FilePathMapping :: new (
539538 self . debugging_opts . remap_path_prefix_from . iter ( ) . zip (
@@ -791,7 +790,7 @@ macro_rules! options {
791790 fn parse_opt_uint( slot: & mut Option <usize >, v: Option <& str >) -> bool {
792791 match v {
793792 Some ( s) => { * slot = s. parse( ) . ok( ) ; slot. is_some( ) }
794- None => { * slot = None ; true }
793+ None => { * slot = None ; false }
795794 }
796795 }
797796
@@ -924,7 +923,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
924923 "metadata to mangle symbol names with" ) ,
925924 extra_filename: String = ( "" . to_string( ) , parse_string, [ UNTRACKED ] ,
926925 "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 ] ,
928927 "divide crate into N units to optimize in parallel" ) ,
929928 remark: Passes = ( SomePasses ( Vec :: new( ) ) , parse_passes, [ UNTRACKED ] ,
930929 "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)
15211520 }
15221521
15231522 let mut cg = build_codegen_options ( matches, error_format) ;
1523+ let mut codegen_units = cg. codegen_units ;
15241524
15251525 // Issue #30063: if user requests llvm-related output to one
15261526 // 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+ }
15381546 }
1539- early_warn ( error_format, "resetting to default -C codegen-units=1" ) ;
1540- cg. codegen_units = 1 ;
1547+ _ => codegen_units = Some ( 1 ) ,
15411548 }
15421549 }
15431550
1544- if cg . codegen_units < 1 {
1551+ if codegen_units == Some ( 0 ) {
15451552 early_error ( error_format, "Value for codegen units must be a positive nonzero integer" ) ;
15461553 }
15471554
@@ -1550,12 +1557,17 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
15501557 // case, but it would be confusing to have the validity of
15511558 // `-Z lto -C codegen-units=2` depend on details of the crate being
15521559 // 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 ) ;
15591571 }
15601572
15611573 if cg. lto && debugging_opts. incremental . is_some ( ) {
@@ -1720,6 +1732,34 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
17201732
17211733 let incremental = debugging_opts. incremental . as_ref ( ) . map ( |m| PathBuf :: from ( m) ) ;
17221734
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+
17231763 ( Options {
17241764 crate_types,
17251765 optimize : opt_level,
@@ -1744,6 +1784,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
17441784 unstable_features : UnstableFeatures :: from_environment ( ) ,
17451785 debug_assertions,
17461786 actually_rustdoc : false ,
1787+ codegen_units,
17471788 } ,
17481789 cfg)
17491790}
@@ -2447,7 +2488,7 @@ mod tests {
24472488 opts. cg . extra_filename = String :: from ( "extra-filename" ) ;
24482489 assert_eq ! ( reference. dep_tracking_hash( ) , opts. dep_tracking_hash( ) ) ;
24492490
2450- opts. cg . codegen_units = 42 ;
2491+ opts. cg . codegen_units = Some ( 42 ) ;
24512492 assert_eq ! ( reference. dep_tracking_hash( ) , opts. dep_tracking_hash( ) ) ;
24522493
24532494 opts. cg . remark = super :: SomePasses ( vec ! [ String :: from( "pass1" ) ,
0 commit comments