From c2b15a6b6416e01378547fa70b343a3b11febf41 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 5 Apr 2021 15:37:11 +0200 Subject: [PATCH] Support -C passes in NewPM And report an error if parsing the additional pass pipeline fails. Threading through the error accounts for most of the changes here. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 17 +++++++++--- compiler/rustc_codegen_llvm/src/back/write.rs | 26 +++++++++++++------ compiler/rustc_codegen_llvm/src/lib.rs | 7 ++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++- compiler/rustc_codegen_ssa/src/back/lto.rs | 2 +- .../rustc_codegen_ssa/src/traits/write.rs | 2 +- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 14 ++++++++-- src/test/ui/invalid/invalid-llvm-passes.rs | 4 +++ .../ui/invalid/invalid-llvm-passes.stderr | 4 +++ 9 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/invalid/invalid-llvm-passes.rs create mode 100644 src/test/ui/invalid/invalid-llvm-passes.stderr diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 48ca7c0060a..f612785e5a4 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -568,10 +568,11 @@ fn thin_lto( pub(crate) fn run_pass_manager( cgcx: &CodegenContext, + diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig, thin: bool, -) { +) -> Result<(), FatalError> { let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &module.name[..]); // Now we have one massive module inside of llmod. Time to run the @@ -584,9 +585,16 @@ pub(crate) fn run_pass_manager( if write::should_use_new_llvm_pass_manager(config) { let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); - write::optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage); + write::optimize_with_new_llvm_pass_manager( + cgcx, + diag_handler, + module, + config, + opt_level, + opt_stage, + )?; debug!("lto done"); - return; + return Ok(()); } let pm = llvm::LLVMCreatePassManager(); @@ -628,6 +636,7 @@ pub(crate) fn run_pass_manager( llvm::LLVMDisposePassManager(pm); } debug!("lto done"); + Ok(()) } pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer); @@ -850,7 +859,7 @@ pub unsafe fn optimize_thin_module( { info!("running thin lto passes over {}", module.name); let config = cgcx.config(module.kind); - run_pass_manager(cgcx, &module, config, true); + run_pass_manager(cgcx, &diag_handler, &module, config, true)?; save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 2b54ad278a2..4219797c5cd 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -415,11 +415,12 @@ pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( cgcx: &CodegenContext, + diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig, opt_level: config::OptLevel, opt_stage: llvm::OptStage, -) { +) -> Result<(), FatalError> { let unroll_loops = opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin; 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( std::ptr::null_mut() }; + let extra_passes = config.passes.join(","); + // FIXME: NewPM doesn't provide a facility to pass custom InlineParams. // We would have to add upstream support for this first, before we can support // config.inline_threshold and our more aggressive default thresholds. - // FIXME: NewPM uses an different and more explicit way to textually represent - // pass pipelines. It would probably make sense to expose this, but it would - // require a different format than the current -C passes. - llvm::LLVMRustOptimizeWithNewPassManager( + let result = llvm::LLVMRustOptimizeWithNewPassManager( module.module_llvm.llmod(), &*module.module_llvm.tm, to_pass_builder_opt_level(opt_level), @@ -477,7 +477,10 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( llvm_selfprofiler, selfprofile_before_pass_callback, selfprofile_after_pass_callback, + extra_passes.as_ptr().cast(), + extra_passes.len(), ); + result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes")) } // Unsafe due to LLVM calls. @@ -486,7 +489,7 @@ pub(crate) unsafe fn optimize( diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig, -) { +) -> Result<(), FatalError> { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]); let llmod = module.module_llvm.llmod(); @@ -511,8 +514,14 @@ pub(crate) unsafe fn optimize( _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, _ => llvm::OptStage::PreLinkNoLTO, }; - optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage); - return; + return optimize_with_new_llvm_pass_manager( + cgcx, + diag_handler, + module, + config, + opt_level, + opt_stage, + ); } if cgcx.prof.llvm_recording_enabled() { @@ -647,6 +656,7 @@ pub(crate) unsafe fn optimize( llvm::LLVMDisposePassManager(fpm); llvm::LLVMDisposePassManager(mpm); } + Ok(()) } unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 5ca4b226c38..bc35aa72965 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -162,7 +162,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { - Ok(back::write::optimize(cgcx, diag_handler, module, config)) + back::write::optimize(cgcx, diag_handler, module, config) } unsafe fn optimize_thin( cgcx: &CodegenContext, @@ -189,8 +189,9 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &ModuleCodegen, config: &ModuleConfig, thin: bool, - ) { - back::lto::run_pass_manager(cgcx, module, config, thin) + ) -> Result<(), FatalError> { + let diag_handler = cgcx.create_diag_handler(); + back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 9c9201aea36..32fdde9b42e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2208,7 +2208,9 @@ extern "C" { llvm_selfprofiler: *mut c_void, begin_callback: SelfProfileBeforePassCallback, end_callback: SelfProfileAfterPassCallback, - ); + ExtraPasses: *const c_char, + ExtraPassesLen: size_t, + ) -> LLVMRustResult; pub fn LLVMRustPrintModule( M: &'a Module, Output: *const c_char, diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index 0ff05229466..d6ae689f254 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -72,7 +72,7 @@ impl LtoModuleCodegen { let module = module.take().unwrap(); { let config = cgcx.config(module.kind); - B::run_lto_pass_manager(cgcx, &module, config, false); + B::run_lto_pass_manager(cgcx, &module, config, false)?; } Ok(module) } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 264e7c2aa92..93fbee2b49b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -58,7 +58,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { llmod: &ModuleCodegen, config: &ModuleConfig, thin: bool, - ); + ) -> Result<(), FatalError>; } pub trait ThinBufferMethods: Send + Sync { diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 355746a5582..99ce13a6ed5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -736,7 +736,7 @@ struct LLVMRustSanitizerOptions { bool SanitizeHWAddressRecover; }; -extern "C" void +extern "C" LLVMRustResult LLVMRustOptimizeWithNewPassManager( LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef, @@ -750,7 +750,8 @@ LLVMRustOptimizeWithNewPassManager( bool InstrumentCoverage, bool InstrumentGCOV, void* LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, - LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { + LLVMRustSelfProfileAfterPassCallback AfterPassCallback, + const char *ExtraPasses, size_t ExtraPassesLen) { Module *TheModule = unwrap(ModuleRef); TargetMachine *TM = unwrap(TMRef); PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust); @@ -1062,6 +1063,14 @@ LLVMRustOptimizeWithNewPassManager( } } + if (ExtraPassesLen) { + if (auto Err = PB.parsePassPipeline(MPM, StringRef(ExtraPasses, ExtraPassesLen))) { + std::string ErrMsg = toString(std::move(Err)); + LLVMRustSetLastError(ErrMsg.c_str()); + return LLVMRustResult::Failure; + } + } + if (NeedThinLTOBufferPasses) { MPM.addPass(CanonicalizeAliasesPass()); MPM.addPass(NameAnonGlobalPass()); @@ -1072,6 +1081,7 @@ LLVMRustOptimizeWithNewPassManager( UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove MPM.run(*TheModule, MAM); + return LLVMRustResult::Success; } // Callback to demangle function name diff --git a/src/test/ui/invalid/invalid-llvm-passes.rs b/src/test/ui/invalid/invalid-llvm-passes.rs new file mode 100644 index 00000000000..ca3c6230af0 --- /dev/null +++ b/src/test/ui/invalid/invalid-llvm-passes.rs @@ -0,0 +1,4 @@ +// build-fail +// compile-flags: -Cpasses=unknown-pass -Z new-llvm-pass-manager=yes + +fn main() {} diff --git a/src/test/ui/invalid/invalid-llvm-passes.stderr b/src/test/ui/invalid/invalid-llvm-passes.stderr new file mode 100644 index 00000000000..ae1f85e41e4 --- /dev/null +++ b/src/test/ui/invalid/invalid-llvm-passes.stderr @@ -0,0 +1,4 @@ +error: failed to run LLVM passes: unknown pass name 'unknown-pass' + +error: aborting due to previous error +