Skip to content

Commit 7a2f446

Browse files
committed
Auto merge of #83894 - nikic:newpm, r=nagisa
Improve support for NewPM This adds various missing bits of support for NewPM and allows us to successfully run stage 2 tests with NewPM enabled. This does not yet enable NewPM by default, as there are still known issue on LLVM 12 (such as a weak fat LTO pipeline). The plan is to make the switch after we update to LLVM 13.
2 parents bba8710 + 1b928ff commit 7a2f446

File tree

14 files changed

+113
-81
lines changed

14 files changed

+113
-81
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

+13-26
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,11 @@ fn thin_lto(
568568

569569
pub(crate) fn run_pass_manager(
570570
cgcx: &CodegenContext<LlvmCodegenBackend>,
571+
diag_handler: &Handler,
571572
module: &ModuleCodegen<ModuleLlvm>,
572573
config: &ModuleConfig,
573574
thin: bool,
574-
) {
575+
) -> Result<(), FatalError> {
575576
let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &module.name[..]);
576577

577578
// Now we have one massive module inside of llmod. Time to run the
@@ -584,15 +585,16 @@ pub(crate) fn run_pass_manager(
584585
if write::should_use_new_llvm_pass_manager(config) {
585586
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
586587
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
587-
// See comment below for why this is necessary.
588-
let opt_level = if let config::OptLevel::No = opt_level {
589-
config::OptLevel::Less
590-
} else {
591-
opt_level
592-
};
593-
write::optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
588+
write::optimize_with_new_llvm_pass_manager(
589+
cgcx,
590+
diag_handler,
591+
module,
592+
config,
593+
opt_level,
594+
opt_stage,
595+
)?;
594596
debug!("lto done");
595-
return;
597+
return Ok(());
596598
}
597599

598600
let pm = llvm::LLVMCreatePassManager();
@@ -603,26 +605,10 @@ pub(crate) fn run_pass_manager(
603605
llvm::LLVMRustAddPass(pm, pass.unwrap());
604606
}
605607

606-
// When optimizing for LTO we don't actually pass in `-O0`, but we force
607-
// it to always happen at least with `-O1`.
608-
//
609-
// With ThinLTO we mess around a lot with symbol visibility in a way
610-
// that will actually cause linking failures if we optimize at O0 which
611-
// notable is lacking in dead code elimination. To ensure we at least
612-
// get some optimizations and correctly link we forcibly switch to `-O1`
613-
// to get dead code elimination.
614-
//
615-
// Note that in general this shouldn't matter too much as you typically
616-
// only turn on ThinLTO when you're compiling with optimizations
617-
// otherwise.
618608
let opt_level = config
619609
.opt_level
620610
.map(|x| to_llvm_opt_settings(x).0)
621611
.unwrap_or(llvm::CodeGenOptLevel::None);
622-
let opt_level = match opt_level {
623-
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
624-
level => level,
625-
};
626612
with_llvm_pmb(module.module_llvm.llmod(), config, opt_level, false, &mut |b| {
627613
if thin {
628614
llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
@@ -650,6 +636,7 @@ pub(crate) fn run_pass_manager(
650636
llvm::LLVMDisposePassManager(pm);
651637
}
652638
debug!("lto done");
639+
Ok(())
653640
}
654641

655642
pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer);
@@ -872,7 +859,7 @@ pub unsafe fn optimize_thin_module(
872859
{
873860
info!("running thin lto passes over {}", module.name);
874861
let config = cgcx.config(module.kind);
875-
run_pass_manager(cgcx, &module, config, true);
862+
run_pass_manager(cgcx, &diag_handler, &module, config, true)?;
876863
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
877864
}
878865
}

compiler/rustc_codegen_llvm/src/back/write.rs

+33-18
Original file line numberDiff line numberDiff line change
@@ -410,16 +410,17 @@ fn get_pgo_use_path(config: &ModuleConfig) -> Option<CString> {
410410

411411
pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
412412
// The new pass manager is disabled by default.
413-
config.new_llvm_pass_manager
413+
config.new_llvm_pass_manager.unwrap_or(false)
414414
}
415415

416416
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
417417
cgcx: &CodegenContext<LlvmCodegenBackend>,
418+
diag_handler: &Handler,
418419
module: &ModuleCodegen<ModuleLlvm>,
419420
config: &ModuleConfig,
420421
opt_level: config::OptLevel,
421422
opt_stage: llvm::OptStage,
422-
) {
423+
) -> Result<(), FatalError> {
423424
let unroll_loops =
424425
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
425426
let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
@@ -449,13 +450,12 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
449450
std::ptr::null_mut()
450451
};
451452

453+
let extra_passes = config.passes.join(",");
454+
452455
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
453456
// We would have to add upstream support for this first, before we can support
454457
// config.inline_threshold and our more aggressive default thresholds.
455-
// FIXME: NewPM uses an different and more explicit way to textually represent
456-
// pass pipelines. It would probably make sense to expose this, but it would
457-
// require a different format than the current -C passes.
458-
llvm::LLVMRustOptimizeWithNewPassManager(
458+
let result = llvm::LLVMRustOptimizeWithNewPassManager(
459459
module.module_llvm.llmod(),
460460
&*module.module_llvm.tm,
461461
to_pass_builder_opt_level(opt_level),
@@ -472,10 +472,15 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
472472
sanitizer_options.as_ref(),
473473
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
474474
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
475+
config.instrument_coverage,
476+
config.instrument_gcov,
475477
llvm_selfprofiler,
476478
selfprofile_before_pass_callback,
477479
selfprofile_after_pass_callback,
480+
extra_passes.as_ptr().cast(),
481+
extra_passes.len(),
478482
);
483+
result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes"))
479484
}
480485

481486
// Unsafe due to LLVM calls.
@@ -484,7 +489,7 @@ pub(crate) unsafe fn optimize(
484489
diag_handler: &Handler,
485490
module: &ModuleCodegen<ModuleLlvm>,
486491
config: &ModuleConfig,
487-
) {
492+
) -> Result<(), FatalError> {
488493
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]);
489494

490495
let llmod = module.module_llvm.llmod();
@@ -509,8 +514,14 @@ pub(crate) unsafe fn optimize(
509514
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
510515
_ => llvm::OptStage::PreLinkNoLTO,
511516
};
512-
optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
513-
return;
517+
return optimize_with_new_llvm_pass_manager(
518+
cgcx,
519+
diag_handler,
520+
module,
521+
config,
522+
opt_level,
523+
opt_stage,
524+
);
514525
}
515526

516527
if cgcx.prof.llvm_recording_enabled() {
@@ -545,15 +556,6 @@ pub(crate) unsafe fn optimize(
545556
llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap());
546557
continue;
547558
}
548-
if pass_name == "insert-gcov-profiling" || pass_name == "instrprof" {
549-
// Instrumentation must be inserted before optimization,
550-
// otherwise LLVM may optimize some functions away which
551-
// breaks llvm-cov.
552-
//
553-
// This mirrors what Clang does in lib/CodeGen/BackendUtil.cpp.
554-
llvm::LLVMRustAddPass(mpm, find_pass(pass_name).unwrap());
555-
continue;
556-
}
557559

558560
if let Some(pass) = find_pass(pass_name) {
559561
extra_passes.push(pass);
@@ -566,6 +568,18 @@ pub(crate) unsafe fn optimize(
566568
}
567569
}
568570

571+
// Instrumentation must be inserted before optimization,
572+
// otherwise LLVM may optimize some functions away which
573+
// breaks llvm-cov.
574+
//
575+
// This mirrors what Clang does in lib/CodeGen/BackendUtil.cpp.
576+
if config.instrument_gcov {
577+
llvm::LLVMRustAddPass(mpm, find_pass("insert-gcov-profiling").unwrap());
578+
}
579+
if config.instrument_coverage {
580+
llvm::LLVMRustAddPass(mpm, find_pass("instrprof").unwrap());
581+
}
582+
569583
add_sanitizer_passes(config, &mut extra_passes);
570584

571585
// Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
@@ -642,6 +656,7 @@ pub(crate) unsafe fn optimize(
642656
llvm::LLVMDisposePassManager(fpm);
643657
llvm::LLVMDisposePassManager(mpm);
644658
}
659+
Ok(())
645660
}
646661

647662
unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {

compiler/rustc_codegen_llvm/src/lib.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
162162
module: &ModuleCodegen<Self::Module>,
163163
config: &ModuleConfig,
164164
) -> Result<(), FatalError> {
165-
Ok(back::write::optimize(cgcx, diag_handler, module, config))
165+
back::write::optimize(cgcx, diag_handler, module, config)
166166
}
167167
unsafe fn optimize_thin(
168168
cgcx: &CodegenContext<Self>,
@@ -189,8 +189,9 @@ impl WriteBackendMethods for LlvmCodegenBackend {
189189
module: &ModuleCodegen<Self::Module>,
190190
config: &ModuleConfig,
191191
thin: bool,
192-
) {
193-
back::lto::run_pass_manager(cgcx, module, config, thin)
192+
) -> Result<(), FatalError> {
193+
let diag_handler = cgcx.create_diag_handler();
194+
back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
194195
}
195196
}
196197

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -2203,10 +2203,14 @@ extern "C" {
22032203
SanitizerOptions: Option<&SanitizerOptions>,
22042204
PGOGenPath: *const c_char,
22052205
PGOUsePath: *const c_char,
2206+
InstrumentCoverage: bool,
2207+
InstrumentGCOV: bool,
22062208
llvm_selfprofiler: *mut c_void,
22072209
begin_callback: SelfProfileBeforePassCallback,
22082210
end_callback: SelfProfileAfterPassCallback,
2209-
);
2211+
ExtraPasses: *const c_char,
2212+
ExtraPassesLen: size_t,
2213+
) -> LLVMRustResult;
22102214
pub fn LLVMRustPrintModule(
22112215
M: &'a Module,
22122216
Output: *const c_char,

compiler/rustc_codegen_ssa/src/back/lto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
7272
let module = module.take().unwrap();
7373
{
7474
let config = cgcx.config(module.kind);
75-
B::run_lto_pass_manager(cgcx, &module, config, false);
75+
B::run_lto_pass_manager(cgcx, &module, config, false)?;
7676
}
7777
Ok(module)
7878
}

compiler/rustc_codegen_ssa/src/back/write.rs

+12-20
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ pub struct ModuleConfig {
8484

8585
pub pgo_gen: SwitchWithOptPath,
8686
pub pgo_use: Option<PathBuf>,
87+
pub instrument_coverage: bool,
88+
pub instrument_gcov: bool,
8789

8890
pub sanitizer: SanitizerSet,
8991
pub sanitizer_recover: SanitizerSet,
@@ -108,7 +110,7 @@ pub struct ModuleConfig {
108110
pub vectorize_slp: bool,
109111
pub merge_functions: bool,
110112
pub inline_threshold: Option<u32>,
111-
pub new_llvm_pass_manager: bool,
113+
pub new_llvm_pass_manager: Option<bool>,
112114
pub emit_lifetime_markers: bool,
113115
}
114116

@@ -165,25 +167,7 @@ impl ModuleConfig {
165167
};
166168

167169
ModuleConfig {
168-
passes: if_regular!(
169-
{
170-
let mut passes = sess.opts.cg.passes.clone();
171-
// compiler_builtins overrides the codegen-units settings,
172-
// which is incompatible with -Zprofile which requires that
173-
// only a single codegen unit is used per crate.
174-
if sess.opts.debugging_opts.profile && !is_compiler_builtins {
175-
passes.push("insert-gcov-profiling".to_owned());
176-
}
177-
178-
// The rustc option `-Zinstrument_coverage` injects intrinsic calls to
179-
// `llvm.instrprof.increment()`, which requires the LLVM `instrprof` pass.
180-
if sess.instrument_coverage() {
181-
passes.push("instrprof".to_owned());
182-
}
183-
passes
184-
},
185-
vec![]
186-
),
170+
passes: if_regular!(sess.opts.cg.passes.clone(), vec![]),
187171

188172
opt_level: opt_level_and_size,
189173
opt_size: opt_level_and_size,
@@ -193,6 +177,14 @@ impl ModuleConfig {
193177
SwitchWithOptPath::Disabled
194178
),
195179
pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None),
180+
instrument_coverage: if_regular!(sess.instrument_coverage(), false),
181+
instrument_gcov: if_regular!(
182+
// compiler_builtins overrides the codegen-units settings,
183+
// which is incompatible with -Zprofile which requires that
184+
// only a single codegen unit is used per crate.
185+
sess.opts.debugging_opts.profile && !is_compiler_builtins,
186+
false
187+
),
196188

197189
sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer, SanitizerSet::empty()),
198190
sanitizer_recover: if_regular!(

compiler/rustc_codegen_ssa/src/traits/write.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
5858
llmod: &ModuleCodegen<Self::Module>,
5959
config: &ModuleConfig,
6060
thin: bool,
61-
);
61+
) -> Result<(), FatalError>;
6262
}
6363

6464
pub trait ThinBufferMethods: Send + Sync {

compiler/rustc_interface/src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ fn test_debugging_options_tracking_hash() {
709709
tracked!(mir_emit_retag, true);
710710
tracked!(mir_opt_level, Some(4));
711711
tracked!(mutable_noalias, Some(true));
712-
tracked!(new_llvm_pass_manager, true);
712+
tracked!(new_llvm_pass_manager, Some(true));
713713
tracked!(no_codegen, true);
714714
tracked!(no_generate_arange_section, true);
715715
tracked!(no_link, true);

0 commit comments

Comments
 (0)