Skip to content

Commit 69ca012

Browse files
committed
Auto merge of #27224 - alexcrichton:configure-lto-right, r=brson
The LTO pass in the compiler forgot to call the `LLVMRustAddBuilderLibraryInfo` function and configure other options such as merge_functions, vectorize_slp, etc. This ended up causing linker errors on MSVC targets because the optimizer didn't have the right knowledge that some system functions are missing on these platforms. This commit consolidates creation of PassManagerBuilder instances to one function which is then called when needed. This ensures that the pass manager is always correctly configured with the various target-specific information that LLVM needs. Overall, this fixes `-C lto -C opt-level=3` on 32-bit MSVC targets.
2 parents c85ba3e + 70e8220 commit 69ca012

File tree

2 files changed

+70
-79
lines changed

2 files changed

+70
-79
lines changed

src/librustc_trans/back/lto.rs

+8-14
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ use llvm::archive_ro::ArchiveRO;
1616
use llvm::{ModuleRef, TargetMachineRef, True, False};
1717
use rustc::metadata::cstore;
1818
use rustc::util::common::time;
19+
use back::write::{ModuleConfig, with_llvm_pmb};
1920

2021
use libc;
2122
use flate;
2223

2324
use std::ffi::CString;
2425

2526
pub fn run(sess: &session::Session, llmod: ModuleRef,
26-
tm: TargetMachineRef, reachable: &[String]) {
27+
tm: TargetMachineRef, reachable: &[String],
28+
config: &ModuleConfig) {
2729
if sess.opts.cg.prefer_dynamic {
2830
sess.err("cannot prefer dynamic linking when performing LTO");
2931
sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
@@ -144,19 +146,11 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
144146
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
145147
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
146148

147-
let opt = match sess.opts.optimize {
148-
config::No => 0,
149-
config::Less => 1,
150-
config::Default => 2,
151-
config::Aggressive => 3,
152-
};
153-
154-
let builder = llvm::LLVMPassManagerBuilderCreate();
155-
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
156-
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
157-
/* Internalize = */ False,
158-
/* RunInliner = */ True);
159-
llvm::LLVMPassManagerBuilderDispose(builder);
149+
with_llvm_pmb(llmod, config, &mut |b| {
150+
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
151+
/* Internalize = */ False,
152+
/* RunInliner = */ True);
153+
});
160154

161155
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
162156

src/librustc_trans/back/write.rs

+62-65
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
249249

250250
/// Module-specific configuration for `optimize_and_codegen`.
251251
#[derive(Clone)]
252-
struct ModuleConfig {
252+
pub struct ModuleConfig {
253253
/// LLVM TargetMachine to use for codegen.
254254
tm: TargetMachineRef,
255255
/// Names of additional optimization passes to run.
@@ -444,72 +444,72 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
444444
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
445445
}
446446

447-
match config.opt_level {
448-
Some(opt_level) => {
449-
// Create the two optimizing pass managers. These mirror what clang
450-
// does, and are by populated by LLVM's default PassManagerBuilder.
451-
// Each manager has a different set of passes, but they also share
452-
// some common passes.
453-
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
454-
let mpm = llvm::LLVMCreatePassManager();
455-
456-
// If we're verifying or linting, add them to the function pass
457-
// manager.
458-
let addpass = |pass: &str| {
459-
let pass = CString::new(pass).unwrap();
460-
llvm::LLVMRustAddPass(fpm, pass.as_ptr())
461-
};
447+
if config.opt_level.is_some() {
448+
// Create the two optimizing pass managers. These mirror what clang
449+
// does, and are by populated by LLVM's default PassManagerBuilder.
450+
// Each manager has a different set of passes, but they also share
451+
// some common passes.
452+
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
453+
let mpm = llvm::LLVMCreatePassManager();
454+
455+
// If we're verifying or linting, add them to the function pass
456+
// manager.
457+
let addpass = |pass: &str| {
458+
let pass = CString::new(pass).unwrap();
459+
llvm::LLVMRustAddPass(fpm, pass.as_ptr())
460+
};
462461

463-
if !config.no_verify { assert!(addpass("verify")); }
464-
if !config.no_prepopulate_passes {
465-
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
466-
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
467-
populate_llvm_passes(fpm, mpm, llmod, opt_level, &config);
468-
}
462+
if !config.no_verify { assert!(addpass("verify")); }
463+
if !config.no_prepopulate_passes {
464+
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
465+
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
466+
with_llvm_pmb(llmod, &config, &mut |b| {
467+
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
468+
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
469+
})
470+
}
469471

470-
for pass in &config.passes {
471-
if !addpass(pass) {
472-
cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
473-
pass));
474-
}
472+
for pass in &config.passes {
473+
if !addpass(pass) {
474+
cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
475+
pass));
475476
}
477+
}
476478

477-
for pass in &cgcx.plugin_passes {
478-
if !addpass(pass) {
479-
cgcx.handler.err(&format!("a plugin asked for LLVM pass \
480-
`{}` but LLVM does not \
481-
recognize it", pass));
482-
}
479+
for pass in &cgcx.plugin_passes {
480+
if !addpass(pass) {
481+
cgcx.handler.err(&format!("a plugin asked for LLVM pass \
482+
`{}` but LLVM does not \
483+
recognize it", pass));
483484
}
485+
}
484486

485-
cgcx.handler.abort_if_errors();
487+
cgcx.handler.abort_if_errors();
486488

487-
// Finally, run the actual optimization passes
488-
time(config.time_passes, "llvm function passes", (), |()|
489-
llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
490-
time(config.time_passes, "llvm module passes", (), |()|
491-
llvm::LLVMRunPassManager(mpm, llmod));
489+
// Finally, run the actual optimization passes
490+
time(config.time_passes, "llvm function passes", (), |()|
491+
llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
492+
time(config.time_passes, "llvm module passes", (), |()|
493+
llvm::LLVMRunPassManager(mpm, llmod));
492494

493-
// Deallocate managers that we're now done with
494-
llvm::LLVMDisposePassManager(fpm);
495-
llvm::LLVMDisposePassManager(mpm);
495+
// Deallocate managers that we're now done with
496+
llvm::LLVMDisposePassManager(fpm);
497+
llvm::LLVMDisposePassManager(mpm);
496498

497-
match cgcx.lto_ctxt {
498-
Some((sess, reachable)) if sess.lto() => {
499-
time(sess.time_passes(), "all lto passes", (), |()|
500-
lto::run(sess, llmod, tm, reachable));
499+
match cgcx.lto_ctxt {
500+
Some((sess, reachable)) if sess.lto() => {
501+
time(sess.time_passes(), "all lto passes", (), |()|
502+
lto::run(sess, llmod, tm, reachable, &config));
501503

502-
if config.emit_lto_bc {
503-
let name = format!("{}.lto.bc", name_extra);
504-
let out = output_names.with_extension(&name);
505-
let out = path2cstr(&out);
506-
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
507-
}
508-
},
509-
_ => {},
510-
}
511-
},
512-
None => {},
504+
if config.emit_lto_bc {
505+
let name = format!("{}.lto.bc", name_extra);
506+
let out = output_names.with_extension(&name);
507+
let out = path2cstr(&out);
508+
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
509+
}
510+
},
511+
_ => {},
512+
}
513513
}
514514

515515
// A codegen-specific pass manager is used to generate object
@@ -1001,15 +1001,14 @@ pub unsafe fn configure_llvm(sess: &Session) {
10011001
llvm_args.as_ptr());
10021002
}
10031003

1004-
unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
1005-
mpm: llvm::PassManagerRef,
1006-
llmod: ModuleRef,
1007-
opt: llvm::CodeGenOptLevel,
1008-
config: &ModuleConfig) {
1004+
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
1005+
config: &ModuleConfig,
1006+
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
10091007
// Create the PassManagerBuilder for LLVM. We configure it with
10101008
// reasonable defaults and prepare it to actually populate the pass
10111009
// manager.
10121010
let builder = llvm::LLVMPassManagerBuilderCreate();
1011+
let opt = config.opt_level.unwrap_or(llvm::CodeGenLevelNone);
10131012

10141013
llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
10151014
config.merge_functions,
@@ -1037,8 +1036,6 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
10371036
}
10381037
}
10391038

1040-
// Use the builder to populate the function/module pass managers.
1041-
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
1042-
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
1039+
f(builder);
10431040
llvm::LLVMPassManagerBuilderDispose(builder);
10441041
}

0 commit comments

Comments
 (0)