1
Fork 0

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.
This commit is contained in:
Nikita Popov 2021-04-05 15:37:11 +02:00
parent 5519cbfe33
commit c2b15a6b64
9 changed files with 60 additions and 20 deletions

View file

@ -568,10 +568,11 @@ fn thin_lto(
pub(crate) fn run_pass_manager( pub(crate) fn run_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>, cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>, module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig, config: &ModuleConfig,
thin: bool, thin: bool,
) { ) -> Result<(), FatalError> {
let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &module.name[..]); 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 // 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) { if write::should_use_new_llvm_pass_manager(config) {
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); 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"); debug!("lto done");
return; return Ok(());
} }
let pm = llvm::LLVMCreatePassManager(); let pm = llvm::LLVMCreatePassManager();
@ -628,6 +636,7 @@ pub(crate) fn run_pass_manager(
llvm::LLVMDisposePassManager(pm); llvm::LLVMDisposePassManager(pm);
} }
debug!("lto done"); debug!("lto done");
Ok(())
} }
pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer); 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); info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind); 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"); save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
} }
} }

View file

@ -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( pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>, cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>, module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig, config: &ModuleConfig,
opt_level: config::OptLevel, opt_level: config::OptLevel,
opt_stage: llvm::OptStage, opt_stage: llvm::OptStage,
) { ) -> Result<(), FatalError> {
let unroll_loops = let unroll_loops =
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin; opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed(); 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() std::ptr::null_mut()
}; };
let extra_passes = config.passes.join(",");
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams. // 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 // We would have to add upstream support for this first, before we can support
// config.inline_threshold and our more aggressive default thresholds. // config.inline_threshold and our more aggressive default thresholds.
// FIXME: NewPM uses an different and more explicit way to textually represent let result = llvm::LLVMRustOptimizeWithNewPassManager(
// pass pipelines. It would probably make sense to expose this, but it would
// require a different format than the current -C passes.
llvm::LLVMRustOptimizeWithNewPassManager(
module.module_llvm.llmod(), module.module_llvm.llmod(),
&*module.module_llvm.tm, &*module.module_llvm.tm,
to_pass_builder_opt_level(opt_level), to_pass_builder_opt_level(opt_level),
@ -477,7 +477,10 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
llvm_selfprofiler, llvm_selfprofiler,
selfprofile_before_pass_callback, selfprofile_before_pass_callback,
selfprofile_after_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. // Unsafe due to LLVM calls.
@ -486,7 +489,7 @@ pub(crate) unsafe fn optimize(
diag_handler: &Handler, diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>, module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig, config: &ModuleConfig,
) { ) -> Result<(), FatalError> {
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]); let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]);
let llmod = module.module_llvm.llmod(); 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, _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
_ => llvm::OptStage::PreLinkNoLTO, _ => llvm::OptStage::PreLinkNoLTO,
}; };
optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage); return optimize_with_new_llvm_pass_manager(
return; cgcx,
diag_handler,
module,
config,
opt_level,
opt_stage,
);
} }
if cgcx.prof.llvm_recording_enabled() { if cgcx.prof.llvm_recording_enabled() {
@ -647,6 +656,7 @@ pub(crate) unsafe fn optimize(
llvm::LLVMDisposePassManager(fpm); llvm::LLVMDisposePassManager(fpm);
llvm::LLVMDisposePassManager(mpm); llvm::LLVMDisposePassManager(mpm);
} }
Ok(())
} }
unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) { unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {

View file

@ -162,7 +162,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
module: &ModuleCodegen<Self::Module>, module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig, config: &ModuleConfig,
) -> Result<(), FatalError> { ) -> Result<(), FatalError> {
Ok(back::write::optimize(cgcx, diag_handler, module, config)) back::write::optimize(cgcx, diag_handler, module, config)
} }
unsafe fn optimize_thin( unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>, cgcx: &CodegenContext<Self>,
@ -189,8 +189,9 @@ impl WriteBackendMethods for LlvmCodegenBackend {
module: &ModuleCodegen<Self::Module>, module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig, config: &ModuleConfig,
thin: bool, thin: bool,
) { ) -> Result<(), FatalError> {
back::lto::run_pass_manager(cgcx, module, config, thin) let diag_handler = cgcx.create_diag_handler();
back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
} }
} }

View file

@ -2208,7 +2208,9 @@ extern "C" {
llvm_selfprofiler: *mut c_void, llvm_selfprofiler: *mut c_void,
begin_callback: SelfProfileBeforePassCallback, begin_callback: SelfProfileBeforePassCallback,
end_callback: SelfProfileAfterPassCallback, end_callback: SelfProfileAfterPassCallback,
); ExtraPasses: *const c_char,
ExtraPassesLen: size_t,
) -> LLVMRustResult;
pub fn LLVMRustPrintModule( pub fn LLVMRustPrintModule(
M: &'a Module, M: &'a Module,
Output: *const c_char, Output: *const c_char,

View file

@ -72,7 +72,7 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
let module = module.take().unwrap(); let module = module.take().unwrap();
{ {
let config = cgcx.config(module.kind); 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) Ok(module)
} }

View file

@ -58,7 +58,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
llmod: &ModuleCodegen<Self::Module>, llmod: &ModuleCodegen<Self::Module>,
config: &ModuleConfig, config: &ModuleConfig,
thin: bool, thin: bool,
); ) -> Result<(), FatalError>;
} }
pub trait ThinBufferMethods: Send + Sync { pub trait ThinBufferMethods: Send + Sync {

View file

@ -736,7 +736,7 @@ struct LLVMRustSanitizerOptions {
bool SanitizeHWAddressRecover; bool SanitizeHWAddressRecover;
}; };
extern "C" void extern "C" LLVMRustResult
LLVMRustOptimizeWithNewPassManager( LLVMRustOptimizeWithNewPassManager(
LLVMModuleRef ModuleRef, LLVMModuleRef ModuleRef,
LLVMTargetMachineRef TMRef, LLVMTargetMachineRef TMRef,
@ -750,7 +750,8 @@ LLVMRustOptimizeWithNewPassManager(
bool InstrumentCoverage, bool InstrumentGCOV, bool InstrumentCoverage, bool InstrumentGCOV,
void* LlvmSelfProfiler, void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
const char *ExtraPasses, size_t ExtraPassesLen) {
Module *TheModule = unwrap(ModuleRef); Module *TheModule = unwrap(ModuleRef);
TargetMachine *TM = unwrap(TMRef); TargetMachine *TM = unwrap(TMRef);
PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust); 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) { if (NeedThinLTOBufferPasses) {
MPM.addPass(CanonicalizeAliasesPass()); MPM.addPass(CanonicalizeAliasesPass());
MPM.addPass(NameAnonGlobalPass()); MPM.addPass(NameAnonGlobalPass());
@ -1072,6 +1081,7 @@ LLVMRustOptimizeWithNewPassManager(
UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove
MPM.run(*TheModule, MAM); MPM.run(*TheModule, MAM);
return LLVMRustResult::Success;
} }
// Callback to demangle function name // Callback to demangle function name

View file

@ -0,0 +1,4 @@
// build-fail
// compile-flags: -Cpasses=unknown-pass -Z new-llvm-pass-manager=yes
fn main() {}

View file

@ -0,0 +1,4 @@
error: failed to run LLVM passes: unknown pass name 'unknown-pass'
error: aborting due to previous error