Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow loading LLVM plugins with both legacy and new pass manager #91125

Merged
merged 5 commits into from
Dec 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::back::write::{
};
use crate::llvm::archive_ro::ArchiveRO;
use crate::llvm::{self, build_string, False, True};
use crate::{LlvmCodegenBackend, ModuleLlvm};
use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::symbol_export;
use rustc_codegen_ssa::back::write::{
Expand Down Expand Up @@ -596,7 +596,10 @@ pub(crate) fn run_pass_manager(
// tools/lto/LTOCodeGenerator.cpp
debug!("running the pass manager");
unsafe {
if write::should_use_new_llvm_pass_manager(cgcx, config) {
if llvm_util::should_use_new_llvm_pass_manager(
&config.new_llvm_pass_manager,
&cgcx.target_arch,
) {
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(
Expand Down
24 changes: 8 additions & 16 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,21 +413,6 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> {
.map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
}

pub(crate) fn should_use_new_llvm_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>,
config: &ModuleConfig,
) -> bool {
// The new pass manager is enabled by default for LLVM >= 13.
// This matches Clang, which also enables it since Clang 13.

// FIXME: There are some perf issues with the new pass manager
// when targeting s390x, so it is temporarily disabled for that
// arch, see https://github.com/rust-lang/rust/issues/89609
config
.new_llvm_pass_manager
.unwrap_or_else(|| cgcx.target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
}

pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
Expand Down Expand Up @@ -470,6 +455,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(

let extra_passes = config.passes.join(",");

let llvm_plugins = config.llvm_plugins.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.
Expand Down Expand Up @@ -499,6 +486,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
selfprofile_after_pass_callback,
extra_passes.as_ptr().cast(),
extra_passes.len(),
llvm_plugins.as_ptr().cast(),
llvm_plugins.len(),
);
result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes"))
}
Expand Down Expand Up @@ -527,7 +516,10 @@ pub(crate) unsafe fn optimize(
}

if let Some(opt_level) = config.opt_level {
if should_use_new_llvm_pass_manager(cgcx, config) {
if llvm_util::should_use_new_llvm_pass_manager(
&config.new_llvm_pass_manager,
&cgcx.target_arch,
) {
let opt_stage = match cgcx.lto {
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2304,6 +2304,8 @@ extern "C" {
end_callback: SelfProfileAfterPassCallback,
ExtraPasses: *const c_char,
ExtraPassesLen: size_t,
LLVMPlugins: *const c_char,
LLVMPluginsLen: size_t,
) -> LLVMRustResult;
pub fn LLVMRustPrintModule(
M: &'a Module,
Expand Down
32 changes: 24 additions & 8 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,20 @@ unsafe fn configure_llvm(sess: &Session) {

llvm::LLVMInitializePasses();

// Register LLVM plugins by loading them into the compiler process.
for plugin in &sess.opts.debugging_opts.llvm_plugins {
let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);

// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
mem::forget(lib);
// Use the legacy plugin registration if we don't use the new pass manager
if !should_use_new_llvm_pass_manager(
&sess.opts.debugging_opts.new_llvm_pass_manager,
&sess.target.arch,
) {
// Register LLVM plugins by loading them into the compiler process.
for plugin in &sess.opts.debugging_opts.llvm_plugins {
let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);

// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
mem::forget(lib);
}
}

rustc_llvm::initialize_available_targets();
Expand Down Expand Up @@ -409,3 +415,13 @@ pub fn tune_cpu(sess: &Session) -> Option<&str> {
let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
Some(handle_native(name))
}

pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_arch: &str) -> bool {
// The new pass manager is enabled by default for LLVM >= 13.
// This matches Clang, which also enables it since Clang 13.

// FIXME: There are some perf issues with the new pass manager
// when targeting s390x, so it is temporarily disabled for that
// arch, see https://github.com/rust-lang/rust/issues/89609
user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
}
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub struct ModuleConfig {
pub inline_threshold: Option<u32>,
pub new_llvm_pass_manager: Option<bool>,
pub emit_lifetime_markers: bool,
pub llvm_plugins: Vec<String>,
}

impl ModuleConfig {
Expand Down Expand Up @@ -260,6 +261,7 @@ impl ModuleConfig {
inline_threshold: sess.opts.cg.inline_threshold,
new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
emit_lifetime_markers: sess.emit_lifetime_markers(),
llvm_plugins: if_regular!(sess.opts.debugging_opts.llvm_plugins.clone(), vec![]),
}
}

Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/FileSystem.h"
Expand Down Expand Up @@ -753,7 +754,8 @@ LLVMRustOptimizeWithNewPassManager(
void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
const char *ExtraPasses, size_t ExtraPassesLen) {
const char *ExtraPasses, size_t ExtraPassesLen,
const char *LLVMPlugins, size_t LLVMPluginsLen) {
Module *TheModule = unwrap(ModuleRef);
TargetMachine *TM = unwrap(TMRef);
OptimizationLevel OptLevel = fromRust(OptLevelRust);
Expand Down Expand Up @@ -924,6 +926,20 @@ LLVMRustOptimizeWithNewPassManager(
}
}

if (LLVMPluginsLen) {
auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen);
SmallVector<StringRef> Plugins;
PluginsStr.split(Plugins, ',', -1, false);
for (auto PluginPath: Plugins) {
auto Plugin = PassPlugin::Load(PluginPath.str());
if (!Plugin) {
LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
continue;
}
Plugin->registerPassBuilderCallbacks(PB);
}
}

#if LLVM_VERSION_GE(13, 0)
ModulePassManager MPM;
#else
Expand Down