about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2018-04-25 15:45:04 +0200
committerMichael Woerister <michaelwoerister@posteo>2018-05-09 16:42:35 +0200
commita9810899a290a7746e88382558454e31bb8f85b7 (patch)
tree82df0e985f6ab1a0f0f24b267e1b00e907812d12
parent8ff4b42064b374bb62043f7729f84b6d979c7667 (diff)
downloadrust-a9810899a290a7746e88382558454e31bb8f85b7.tar.gz
rust-a9810899a290a7746e88382558454e31bb8f85b7.zip
Allow for specifying a linker plugin for cross-language LTO
-rw-r--r--src/librustc/session/config.rs55
-rw-r--r--src/librustc/session/mod.rs7
-rw-r--r--src/librustc_trans/back/link.rs3
-rw-r--r--src/librustc_trans/back/linker.rs52
-rw-r--r--src/librustc_trans/back/write.rs10
-rw-r--r--src/test/run-make/cross-lang-lto/Makefile4
6 files changed, 118 insertions, 13 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 83dac033f94..245663494dd 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -95,6 +95,23 @@ pub enum Lto {
     Fat,
 }
 
+#[derive(Clone, PartialEq, Hash)]
+pub enum CrossLangLto {
+    LinkerPlugin(PathBuf),
+    NoLink,
+    Disabled
+}
+
+impl CrossLangLto {
+    pub fn embed_bitcode(&self) -> bool {
+        match *self {
+            CrossLangLto::LinkerPlugin(_) |
+            CrossLangLto::NoLink => true,
+            CrossLangLto::Disabled => false,
+        }
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Hash)]
 pub enum DebugInfoLevel {
     NoDebugInfo,
@@ -412,6 +429,7 @@ top_level_options!(
 
         // Remap source path prefixes in all output (messages, object files, debug, etc)
         remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+
         edition: Edition [TRACKED],
     }
 );
@@ -777,11 +795,15 @@ macro_rules! options {
             Some("`string` or `string=string`");
         pub const parse_lto: Option<&'static str> =
             Some("one of `thin`, `fat`, or omitted");
+        pub const parse_cross_lang_lto: Option<&'static str> =
+            Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \
+                  or the path to the linker plugin");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
-        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
+        use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
+                    CrossLangLto};
         use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
         use std::path::PathBuf;
 
@@ -986,6 +1008,26 @@ macro_rules! options {
             true
         }
 
+        fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool {
+            if v.is_some() {
+                let mut bool_arg = None;
+                if parse_opt_bool(&mut bool_arg, v) {
+                    *slot = if bool_arg.unwrap() {
+                        CrossLangLto::NoLink
+                    } else {
+                        CrossLangLto::Disabled
+                    };
+                    return true
+                }
+            }
+
+            *slot = match v {
+                None |
+                Some("no-link") => CrossLangLto::NoLink,
+                Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
+            };
+            true
+        }
     }
 ) }
 
@@ -1295,7 +1337,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "make the current crate share its generic instantiations"),
     chalk: bool = (false, parse_bool, [TRACKED],
           "enable the experimental Chalk-based trait solving engine"),
-    cross_lang_lto: bool = (false, parse_bool, [TRACKED],
+    cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED],
           "generate build artifacts that are compatible with linker-based LTO."),
 }
 
@@ -2327,7 +2369,7 @@ mod dep_tracking {
     use std::path::PathBuf;
     use std::collections::hash_map::DefaultHasher;
     use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
-                Passes, Sanitizer};
+                Passes, Sanitizer, CrossLangLto};
     use syntax::feature_gate::UnstableFeatures;
     use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
     use syntax::edition::Edition;
@@ -2391,6 +2433,7 @@ mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
     impl_dep_tracking_hash_via_hash!(TargetTriple);
     impl_dep_tracking_hash_via_hash!(Edition);
+    impl_dep_tracking_hash_via_hash!(CrossLangLto);
 
     impl_dep_tracking_hash_for_sortable_vec_of!(String);
     impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
@@ -2455,7 +2498,7 @@ mod tests {
     use lint;
     use middle::cstore;
     use session::config::{build_configuration, build_session_options_and_crate_config};
-    use session::config::Lto;
+    use session::config::{Lto, CrossLangLto};
     use session::build_session;
     use std::collections::{BTreeMap, BTreeSet};
     use std::iter::FromIterator;
@@ -3111,6 +3154,10 @@ mod tests {
         opts = reference.clone();
         opts.debugging_opts.relro_level = Some(RelroLevel::Full);
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+        opts = reference.clone();
+        opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
+        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
     }
 
     #[test]
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 2ab72ba20bf..23f84881c79 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -657,6 +657,13 @@ impl Session {
         }
     }
 
+    pub fn target_cpu(&self) -> &str {
+        match self.opts.cg.target_cpu {
+            Some(ref s) => &**s,
+            None => &*self.target.target.options.cpu
+        }
+    }
+
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         if let Some(x) = self.opts.cg.force_frame_pointers {
             x
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 92f9a9e8ba9..d39556e9bb1 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -970,6 +970,9 @@ fn link_args(cmd: &mut Linker,
              out_filename: &Path,
              trans: &CrateTranslation) {
 
+    // Linker plugins should be specified early in the list of arguments
+    cmd.cross_lang_lto();
+
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
     let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index ea3f5b40860..2a84ffe79b2 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -21,7 +21,8 @@ use back::symbol_export;
 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
 use rustc::middle::dependency_format::Linkage;
 use rustc::session::Session;
-use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
+use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel,
+                             CrossLangLto};
 use rustc::ty::TyCtxt;
 use rustc_target::spec::{LinkerFlavor, LldFlavor};
 use serialize::{json, Encoder};
@@ -127,6 +128,7 @@ pub trait Linker {
     fn subsystem(&mut self, subsystem: &str);
     fn group_start(&mut self);
     fn group_end(&mut self);
+    fn cross_lang_lto(&mut self);
     // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
     fn finalize(&mut self) -> Command;
 }
@@ -434,6 +436,42 @@ impl<'a> Linker for GccLinker<'a> {
             self.linker_arg("--end-group");
         }
     }
+
+    fn cross_lang_lto(&mut self) {
+        match self.sess.opts.debugging_opts.cross_lang_lto {
+            CrossLangLto::Disabled |
+            CrossLangLto::NoLink => {
+                // Nothing to do
+            }
+            CrossLangLto::LinkerPlugin(ref path) => {
+                self.linker_arg(&format!("-plugin={}", path.display()));
+
+                let opt_level = match self.sess.opts.optimize {
+                    config::OptLevel::No => "O0",
+                    config::OptLevel::Less => "O1",
+                    config::OptLevel::Default => "O2",
+                    config::OptLevel::Aggressive => "O3",
+                    config::OptLevel::Size => "Os",
+                    config::OptLevel::SizeMin => "Oz",
+                };
+
+                self.linker_arg(&format!("-plugin-opt={}", opt_level));
+                self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu()));
+
+                match self.sess.opts.cg.lto {
+                    config::Lto::Thin |
+                    config::Lto::ThinLocal => {
+                        self.linker_arg(&format!("-plugin-opt=thin"));
+                    }
+                    config::Lto::Fat |
+                    config::Lto::Yes |
+                    config::Lto::No => {
+                        // default to regular LTO
+                    }
+                }
+            }
+        }
+    }
 }
 
 pub struct MsvcLinker<'a> {
@@ -666,6 +704,10 @@ impl<'a> Linker for MsvcLinker<'a> {
     // MSVC doesn't need group indicators
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
+
+    fn cross_lang_lto(&mut self) {
+        // Do nothing
+    }
 }
 
 pub struct EmLinker<'a> {
@@ -832,6 +874,10 @@ impl<'a> Linker for EmLinker<'a> {
     // Appears not necessary on Emscripten
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
+
+    fn cross_lang_lto(&mut self) {
+        // Do nothing
+    }
 }
 
 fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
@@ -984,4 +1030,8 @@ impl Linker for WasmLd {
     // Not needed for now with LLD
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
+
+    fn cross_lang_lto(&mut self) {
+        // Do nothing for now
+    }
 }
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index b6fae3eaff2..64876e82309 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -174,10 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
     let triple = &sess.target.target.llvm_target;
 
     let triple = CString::new(triple.as_bytes()).unwrap();
-    let cpu = match sess.opts.cg.target_cpu {
-        Some(ref s) => &**s,
-        None => &*sess.target.target.options.cpu
-    };
+    let cpu = sess.target_cpu();
     let cpu = CString::new(cpu.as_bytes()).unwrap();
     let features = attributes::llvm_target_features(sess)
         .collect::<Vec<_>>()
@@ -294,7 +291,7 @@ impl ModuleConfig {
         self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
         let embed_bitcode = sess.target.target.options.embed_bitcode ||
                             sess.opts.debugging_opts.embed_bitcode ||
-                            sess.opts.debugging_opts.cross_lang_lto;
+                            sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
         if embed_bitcode {
             match sess.opts.optimize {
                 config::OptLevel::No |
@@ -1358,7 +1355,8 @@ fn execute_work_item(cgcx: &CodegenContext,
 
             // Don't run LTO passes when cross-lang LTO is enabled. The linker
             // will do that for us in this case.
-            let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto;
+            let needs_lto = needs_lto &&
+                !cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
 
             if needs_lto {
                 Ok(WorkItemResult::NeedsLTO(mtrans))
diff --git a/src/test/run-make/cross-lang-lto/Makefile b/src/test/run-make/cross-lang-lto/Makefile
index 98b509cd81f..925f686fe11 100644
--- a/src/test/run-make/cross-lang-lto/Makefile
+++ b/src/test/run-make/cross-lang-lto/Makefile
@@ -18,9 +18,9 @@ endif
 OBJDUMP=llvm-objdump
 SECTION_HEADERS=$(OBJDUMP) -section-headers
 
-BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1
+BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1
 
-BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj
+BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
 
 all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib