Skip to content

Commit

Permalink
Auto merge of #45666 - Amanieu:tls-model, r=alexcrichton
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Nov 7, 2017
2 parents 3e7f501 + fdf7ba2 commit 7ade24f
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 13 deletions.
16 changes: 14 additions & 2 deletions src/librustc/session/config.rs
Expand Up @@ -368,6 +368,7 @@ pub enum PrintRequest {
TargetFeatures,
RelocationModels,
CodeModels,
TlsModels,
TargetSpec,
NativeStaticLibs,
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -2520,6 +2528,10 @@ mod tests {
opts.cg.code_model = Some(String::from("code model"));
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());
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_back/target/mod.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_driver/lib.rs
Expand Up @@ -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] = [];
}
}
}
Expand Down Expand Up @@ -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);
}
Expand Down
12 changes: 12 additions & 0 deletions src/librustc_llvm/ffi.rs
Expand Up @@ -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 {}
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_llvm/lib.rs
Expand Up @@ -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) {
Expand Down
11 changes: 8 additions & 3 deletions src/librustc_trans/back/write.rs
Expand Up @@ -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)),
Expand Down Expand Up @@ -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!();
}
Expand Down
9 changes: 4 additions & 5 deletions src/librustc_trans/consts.rs
Expand Up @@ -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());
}
}

Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
30 changes: 27 additions & 3 deletions src/librustc_trans/context.rs
Expand Up @@ -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`
Expand Down Expand Up @@ -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!();
}
Expand Down Expand Up @@ -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,
}
}

Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 7ade24f

Please sign in to comment.