about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-07 14:24:15 +0000
committerbors <bors@rust-lang.org>2017-11-07 14:24:15 +0000
commit7ade24f67201531778e7674b4b63ebf1a23c9643 (patch)
tree0f0035aa423331057bcf87ffbad38a34972a5450
parent3e7f501991df2f7fc87f6c340945112c128735d2 (diff)
parentfdf7ba2ce9e304a21d50adf41643da28268fd6fc (diff)
downloadrust-7ade24f67201531778e7674b4b63ebf1a23c9643.tar.gz
rust-7ade24f67201531778e7674b4b63ebf1a23c9643.zip
Auto merge of #45666 - Amanieu:tls-model, r=alexcrichton
Allow overriding the TLS model

This PR adds the ability to override the default "global-dynamic" TLS model with a more specific one through a target json option or a command-line option. This allows for better code generation in certain situations.

This is similar to the `-ftls-model=` option in GCC and Clang.
-rw-r--r--src/librustc/session/config.rs16
-rw-r--r--src/librustc_back/target/mod.rs6
-rw-r--r--src/librustc_driver/lib.rs8
-rw-r--r--src/librustc_llvm/ffi.rs12
-rw-r--r--src/librustc_llvm/lib.rs5
-rw-r--r--src/librustc_trans/back/write.rs11
-rw-r--r--src/librustc_trans/consts.rs9
-rw-r--r--src/librustc_trans/context.rs30
8 files changed, 84 insertions, 13 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index c4fc30429e0..9f50afde145 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -368,6 +368,7 @@ pub enum PrintRequest {
     TargetFeatures,
     RelocationModels,
     CodeModels,
+    TlsModels,
     TargetSpec,
     NativeStaticLibs,
 }
@@ -1104,6 +1105,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "enable ThinLTO when possible"),
     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "control whether #[inline] functions are in all cgus"),
+    tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
+         "choose the TLS model to use (rustc --print tls-models for details)"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -1330,7 +1333,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
                                print on stdout",
                      "[crate-name|file-names|sysroot|cfg|target-list|\
                        target-cpus|target-features|relocation-models|\
-                       code-models|target-spec-json|native-static-libs]"),
+                       code-models|tls-models|target-spec-json|native-static-libs]"),
         opt::flagmulti_s("g",  "",  "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
@@ -1473,7 +1476,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         })
     });
 
-    let debugging_opts = build_debugging_options(matches, error_format);
+    let mut debugging_opts = build_debugging_options(matches, error_format);
 
     if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
         early_error(ErrorOutputType::Json(false),
@@ -1579,6 +1582,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         prints.push(PrintRequest::CodeModels);
         cg.code_model = None;
     }
+    if debugging_opts.tls_model.as_ref().map_or(false, |s| s == "help") {
+        prints.push(PrintRequest::TlsModels);
+        debugging_opts.tls_model = None;
+    }
 
     let cg = cg;
 
@@ -1678,6 +1685,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
             "target-features" => PrintRequest::TargetFeatures,
             "relocation-models" => PrintRequest::RelocationModels,
             "code-models" => PrintRequest::CodeModels,
+            "tls-models" => PrintRequest::TlsModels,
             "native-static-libs" => PrintRequest::NativeStaticLibs,
             "target-spec-json" => {
                 if nightly_options::is_unstable_enabled(matches) {
@@ -2521,6 +2529,10 @@ mod tests {
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
         opts = reference.clone();
+        opts.debugging_opts.tls_model = Some(String::from("tls model"));
+        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+        opts = reference.clone();
         opts.cg.metadata = vec![String::from("A"), String::from("B")];
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index a56d0678158..8fd4aad89c6 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -311,6 +311,9 @@ pub struct TargetOptions {
     pub relocation_model: String,
     /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default".
     pub code_model: String,
+    /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec"
+    /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang.
+    pub tls_model: String,
     /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
     pub disable_redzone: bool,
     /// Eliminate frame pointers from stack frames if possible. Defaults to true.
@@ -450,6 +453,7 @@ impl Default for TargetOptions {
             executables: false,
             relocation_model: "pic".to_string(),
             code_model: "default".to_string(),
+            tls_model: "global-dynamic".to_string(),
             disable_redzone: false,
             eliminate_frame_pointer: true,
             function_sections: true,
@@ -696,6 +700,7 @@ impl Target {
         key!(executables, bool);
         key!(relocation_model);
         key!(code_model);
+        key!(tls_model);
         key!(disable_redzone, bool);
         key!(eliminate_frame_pointer, bool);
         key!(function_sections, bool);
@@ -888,6 +893,7 @@ impl ToJson for Target {
         target_option_val!(executables);
         target_option_val!(relocation_model);
         target_option_val!(code_model);
+        target_option_val!(tls_model);
         target_option_val!(disable_redzone);
         target_option_val!(eliminate_frame_pointer);
         target_option_val!(function_sections);
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index fc503f4eb4b..c5cce70c945 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -177,6 +177,7 @@ mod rustc_trans {
         pub mod write {
             pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = [];
             pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = [];
+            pub const TLS_MODEL_ARGS: [(&'static str, ()); 0] = [];
         }
     }
 }
@@ -797,6 +798,13 @@ impl RustcDefaultCalls {
                     }
                     println!("");
                 }
+                PrintRequest::TlsModels => {
+                    println!("Available TLS models:");
+                    for &(name, _) in rustc_trans::back::write::TLS_MODEL_ARGS.iter(){
+                        println!("    {}", name);
+                    }
+                    println!("");
+                }
                 PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => {
                     rustc_trans::print(*req, sess);
                 }
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 3399bf2acd8..ac0e4dde0c1 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -359,6 +359,17 @@ pub struct ThinLTOModule {
     pub len: usize,
 }
 
+/// LLVMThreadLocalMode
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum ThreadLocalMode {
+  NotThreadLocal,
+  GeneralDynamic,
+  LocalDynamic,
+  InitialExec,
+  LocalExec
+}
+
 // Opaque pointer types
 #[allow(missing_copy_implementations)]
 pub enum Module_opaque {}
@@ -709,6 +720,7 @@ extern "C" {
     pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef;
     pub fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef);
     pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool);
+    pub fn LLVMSetThreadLocalMode(GlobalVar: ValueRef, Mode: ThreadLocalMode);
     pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool;
     pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool);
     pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef;
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 98172bca177..5ccce8de706 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -172,6 +172,11 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) {
         LLVMSetThreadLocal(global, is_thread_local as Bool);
     }
 }
+pub fn set_thread_local_mode(global: ValueRef, mode: ThreadLocalMode) {
+    unsafe {
+        LLVMSetThreadLocalMode(global, mode);
+    }
+}
 
 impl Attribute {
     pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 10475a2b1b1..d59d8ca1a78 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -76,6 +76,13 @@ pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [
     ("large", llvm::CodeModel::Large),
 ];
 
+pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [
+    ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
+    ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
+    ("initial-exec", llvm::ThreadLocalMode::InitialExec),
+    ("local-exec", llvm::ThreadLocalMode::LocalExec),
+];
+
 pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
     match llvm::last_error() {
         Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
@@ -173,9 +180,7 @@ pub fn target_machine_factory(sess: &Session)
         Some(x) => x.1,
         _ => {
             sess.err(&format!("{:?} is not a valid code model",
-                             sess.opts
-                                 .cg
-                                 .code_model));
+                              code_model_arg));
             sess.abort_if_errors();
             bug!();
         }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index eaf7392aab5..4ae289cfada 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -196,7 +196,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
 
         for attr in attrs {
             if attr.check_name("thread_local") {
-                llvm::set_thread_local(g, true);
+                llvm::set_thread_local_mode(g, ccx.tls_model());
             }
         }
 
@@ -215,7 +215,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
         // symbol and another one doesn't.
         for attr in ccx.tcx().get_attrs(def_id).iter() {
             if attr.check_name("thread_local") {
-                llvm::set_thread_local(g, true);
+                llvm::set_thread_local_mode(g, ccx.tls_model());
             }
         }
         if ccx.use_dll_storage_attrs() && !ccx.tcx().is_foreign_item(def_id) {
@@ -305,9 +305,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
         debuginfo::create_global_var_metadata(ccx, id, g);
 
-        if attr::contains_name(attrs,
-                               "thread_local") {
-            llvm::set_thread_local(g, true);
+        if attr::contains_name(attrs, "thread_local") {
+            llvm::set_thread_local_mode(g, ccx.tls_model());
         }
 
         base::set_link_section(ccx, g, attrs);
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 9df057c77a9..cb71ef104d3 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -52,6 +52,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     check_overflow: bool,
     use_dll_storage_attrs: bool,
+    tls_model: llvm::ThreadLocalMode,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
@@ -159,9 +160,25 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode {
         Some(x) => x.1,
         _ => {
             sess.err(&format!("{:?} is not a valid relocation mode",
-                             sess.opts
-                                 .cg
-                                 .code_model));
+                              reloc_model_arg));
+            sess.abort_if_errors();
+            bug!();
+        }
+    }
+}
+
+fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode {
+    let tls_model_arg = match sess.opts.debugging_opts.tls_model {
+        Some(ref s) => &s[..],
+        None => &sess.target.target.options.tls_model[..],
+    };
+
+    match ::back::write::TLS_MODEL_ARGS.iter().find(
+        |&&arg| arg.0 == tls_model_arg) {
+        Some(x) => x.1,
+        _ => {
+            sess.err(&format!("{:?} is not a valid TLS model",
+                              tls_model_arg));
             sess.abort_if_errors();
             bug!();
         }
@@ -283,10 +300,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
 
         let check_overflow = tcx.sess.overflow_checks();
 
+        let tls_model = get_tls_model(&tcx.sess);
+
         SharedCrateContext {
             tcx,
             check_overflow,
             use_dll_storage_attrs,
+            tls_model,
         }
     }
 
@@ -528,6 +548,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         self.shared.use_dll_storage_attrs()
     }
 
+    pub fn tls_model(&self) -> llvm::ThreadLocalMode {
+        self.shared.tls_model
+    }
+
     /// Generate a new symbol name with the given prefix. This symbol name must
     /// only be used for definitions with `internal` or `private` linkage.
     pub fn generate_local_symbol_name(&self, prefix: &str) -> String {