Skip to content

Commit a981089

Browse files
Allow for specifying a linker plugin for cross-language LTO
1 parent 8ff4b42 commit a981089

File tree

6 files changed

+118
-13
lines changed

6 files changed

+118
-13
lines changed

src/librustc/session/config.rs

+51-4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,23 @@ pub enum Lto {
9595
Fat,
9696
}
9797

98+
#[derive(Clone, PartialEq, Hash)]
99+
pub enum CrossLangLto {
100+
LinkerPlugin(PathBuf),
101+
NoLink,
102+
Disabled
103+
}
104+
105+
impl CrossLangLto {
106+
pub fn embed_bitcode(&self) -> bool {
107+
match *self {
108+
CrossLangLto::LinkerPlugin(_) |
109+
CrossLangLto::NoLink => true,
110+
CrossLangLto::Disabled => false,
111+
}
112+
}
113+
}
114+
98115
#[derive(Clone, Copy, PartialEq, Hash)]
99116
pub enum DebugInfoLevel {
100117
NoDebugInfo,
@@ -412,6 +429,7 @@ top_level_options!(
412429

413430
// Remap source path prefixes in all output (messages, object files, debug, etc)
414431
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
432+
415433
edition: Edition [TRACKED],
416434
}
417435
);
@@ -777,11 +795,15 @@ macro_rules! options {
777795
Some("`string` or `string=string`");
778796
pub const parse_lto: Option<&'static str> =
779797
Some("one of `thin`, `fat`, or omitted");
798+
pub const parse_cross_lang_lto: Option<&'static str> =
799+
Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \
800+
or the path to the linker plugin");
780801
}
781802

782803
#[allow(dead_code)]
783804
mod $mod_set {
784-
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
805+
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
806+
CrossLangLto};
785807
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
786808
use std::path::PathBuf;
787809

@@ -986,6 +1008,26 @@ macro_rules! options {
9861008
true
9871009
}
9881010

1011+
fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool {
1012+
if v.is_some() {
1013+
let mut bool_arg = None;
1014+
if parse_opt_bool(&mut bool_arg, v) {
1015+
*slot = if bool_arg.unwrap() {
1016+
CrossLangLto::NoLink
1017+
} else {
1018+
CrossLangLto::Disabled
1019+
};
1020+
return true
1021+
}
1022+
}
1023+
1024+
*slot = match v {
1025+
None |
1026+
Some("no-link") => CrossLangLto::NoLink,
1027+
Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
1028+
};
1029+
true
1030+
}
9891031
}
9901032
) }
9911033

@@ -1295,7 +1337,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
12951337
"make the current crate share its generic instantiations"),
12961338
chalk: bool = (false, parse_bool, [TRACKED],
12971339
"enable the experimental Chalk-based trait solving engine"),
1298-
cross_lang_lto: bool = (false, parse_bool, [TRACKED],
1340+
cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED],
12991341
"generate build artifacts that are compatible with linker-based LTO."),
13001342
}
13011343

@@ -2327,7 +2369,7 @@ mod dep_tracking {
23272369
use std::path::PathBuf;
23282370
use std::collections::hash_map::DefaultHasher;
23292371
use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
2330-
Passes, Sanitizer};
2372+
Passes, Sanitizer, CrossLangLto};
23312373
use syntax::feature_gate::UnstableFeatures;
23322374
use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
23332375
use syntax::edition::Edition;
@@ -2391,6 +2433,7 @@ mod dep_tracking {
23912433
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
23922434
impl_dep_tracking_hash_via_hash!(TargetTriple);
23932435
impl_dep_tracking_hash_via_hash!(Edition);
2436+
impl_dep_tracking_hash_via_hash!(CrossLangLto);
23942437

23952438
impl_dep_tracking_hash_for_sortable_vec_of!(String);
23962439
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
@@ -2455,7 +2498,7 @@ mod tests {
24552498
use lint;
24562499
use middle::cstore;
24572500
use session::config::{build_configuration, build_session_options_and_crate_config};
2458-
use session::config::Lto;
2501+
use session::config::{Lto, CrossLangLto};
24592502
use session::build_session;
24602503
use std::collections::{BTreeMap, BTreeSet};
24612504
use std::iter::FromIterator;
@@ -3111,6 +3154,10 @@ mod tests {
31113154
opts = reference.clone();
31123155
opts.debugging_opts.relro_level = Some(RelroLevel::Full);
31133156
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3157+
3158+
opts = reference.clone();
3159+
opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
3160+
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
31143161
}
31153162

31163163
#[test]

src/librustc/session/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,13 @@ impl Session {
657657
}
658658
}
659659

660+
pub fn target_cpu(&self) -> &str {
661+
match self.opts.cg.target_cpu {
662+
Some(ref s) => &**s,
663+
None => &*self.target.target.options.cpu
664+
}
665+
}
666+
660667
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
661668
if let Some(x) = self.opts.cg.force_frame_pointers {
662669
x

src/librustc_trans/back/link.rs

+3
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,9 @@ fn link_args(cmd: &mut Linker,
970970
out_filename: &Path,
971971
trans: &CrateTranslation) {
972972

973+
// Linker plugins should be specified early in the list of arguments
974+
cmd.cross_lang_lto();
975+
973976
// The default library location, we need this to find the runtime.
974977
// The location of crates will be determined as needed.
975978
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();

src/librustc_trans/back/linker.rs

+51-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use back::symbol_export;
2121
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
2222
use rustc::middle::dependency_format::Linkage;
2323
use rustc::session::Session;
24-
use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
24+
use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel,
25+
CrossLangLto};
2526
use rustc::ty::TyCtxt;
2627
use rustc_target::spec::{LinkerFlavor, LldFlavor};
2728
use serialize::{json, Encoder};
@@ -127,6 +128,7 @@ pub trait Linker {
127128
fn subsystem(&mut self, subsystem: &str);
128129
fn group_start(&mut self);
129130
fn group_end(&mut self);
131+
fn cross_lang_lto(&mut self);
130132
// Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
131133
fn finalize(&mut self) -> Command;
132134
}
@@ -434,6 +436,42 @@ impl<'a> Linker for GccLinker<'a> {
434436
self.linker_arg("--end-group");
435437
}
436438
}
439+
440+
fn cross_lang_lto(&mut self) {
441+
match self.sess.opts.debugging_opts.cross_lang_lto {
442+
CrossLangLto::Disabled |
443+
CrossLangLto::NoLink => {
444+
// Nothing to do
445+
}
446+
CrossLangLto::LinkerPlugin(ref path) => {
447+
self.linker_arg(&format!("-plugin={}", path.display()));
448+
449+
let opt_level = match self.sess.opts.optimize {
450+
config::OptLevel::No => "O0",
451+
config::OptLevel::Less => "O1",
452+
config::OptLevel::Default => "O2",
453+
config::OptLevel::Aggressive => "O3",
454+
config::OptLevel::Size => "Os",
455+
config::OptLevel::SizeMin => "Oz",
456+
};
457+
458+
self.linker_arg(&format!("-plugin-opt={}", opt_level));
459+
self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu()));
460+
461+
match self.sess.opts.cg.lto {
462+
config::Lto::Thin |
463+
config::Lto::ThinLocal => {
464+
self.linker_arg(&format!("-plugin-opt=thin"));
465+
}
466+
config::Lto::Fat |
467+
config::Lto::Yes |
468+
config::Lto::No => {
469+
// default to regular LTO
470+
}
471+
}
472+
}
473+
}
474+
}
437475
}
438476

439477
pub struct MsvcLinker<'a> {
@@ -666,6 +704,10 @@ impl<'a> Linker for MsvcLinker<'a> {
666704
// MSVC doesn't need group indicators
667705
fn group_start(&mut self) {}
668706
fn group_end(&mut self) {}
707+
708+
fn cross_lang_lto(&mut self) {
709+
// Do nothing
710+
}
669711
}
670712

671713
pub struct EmLinker<'a> {
@@ -832,6 +874,10 @@ impl<'a> Linker for EmLinker<'a> {
832874
// Appears not necessary on Emscripten
833875
fn group_start(&mut self) {}
834876
fn group_end(&mut self) {}
877+
878+
fn cross_lang_lto(&mut self) {
879+
// Do nothing
880+
}
835881
}
836882

837883
fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
@@ -984,4 +1030,8 @@ impl Linker for WasmLd {
9841030
// Not needed for now with LLD
9851031
fn group_start(&mut self) {}
9861032
fn group_end(&mut self) {}
1033+
1034+
fn cross_lang_lto(&mut self) {
1035+
// Do nothing for now
1036+
}
9871037
}

src/librustc_trans/back/write.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
174174
let triple = &sess.target.target.llvm_target;
175175

176176
let triple = CString::new(triple.as_bytes()).unwrap();
177-
let cpu = match sess.opts.cg.target_cpu {
178-
Some(ref s) => &**s,
179-
None => &*sess.target.target.options.cpu
180-
};
177+
let cpu = sess.target_cpu();
181178
let cpu = CString::new(cpu.as_bytes()).unwrap();
182179
let features = attributes::llvm_target_features(sess)
183180
.collect::<Vec<_>>()
@@ -294,7 +291,7 @@ impl ModuleConfig {
294291
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
295292
let embed_bitcode = sess.target.target.options.embed_bitcode ||
296293
sess.opts.debugging_opts.embed_bitcode ||
297-
sess.opts.debugging_opts.cross_lang_lto;
294+
sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
298295
if embed_bitcode {
299296
match sess.opts.optimize {
300297
config::OptLevel::No |
@@ -1358,7 +1355,8 @@ fn execute_work_item(cgcx: &CodegenContext,
13581355

13591356
// Don't run LTO passes when cross-lang LTO is enabled. The linker
13601357
// will do that for us in this case.
1361-
let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto;
1358+
let needs_lto = needs_lto &&
1359+
!cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
13621360

13631361
if needs_lto {
13641362
Ok(WorkItemResult::NeedsLTO(mtrans))

src/test/run-make/cross-lang-lto/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ endif
1818
OBJDUMP=llvm-objdump
1919
SECTION_HEADERS=$(OBJDUMP) -section-headers
2020

21-
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1
21+
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1
2222

23-
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj
23+
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
2424

2525
all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib
2626

0 commit comments

Comments
 (0)