Skip to content

Commit 7ade24f

Browse files
committed
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.
2 parents 3e7f501 + fdf7ba2 commit 7ade24f

File tree

8 files changed

+84
-13
lines changed

8 files changed

+84
-13
lines changed

src/librustc/session/config.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ pub enum PrintRequest {
368368
TargetFeatures,
369369
RelocationModels,
370370
CodeModels,
371+
TlsModels,
371372
TargetSpec,
372373
NativeStaticLibs,
373374
}
@@ -1104,6 +1105,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
11041105
"enable ThinLTO when possible"),
11051106
inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
11061107
"control whether #[inline] functions are in all cgus"),
1108+
tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1109+
"choose the TLS model to use (rustc --print tls-models for details)"),
11071110
}
11081111

11091112
pub fn default_lib_output() -> CrateType {
@@ -1330,7 +1333,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
13301333
print on stdout",
13311334
"[crate-name|file-names|sysroot|cfg|target-list|\
13321335
target-cpus|target-features|relocation-models|\
1333-
code-models|target-spec-json|native-static-libs]"),
1336+
code-models|tls-models|target-spec-json|native-static-libs]"),
13341337
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
13351338
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
13361339
opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
@@ -1473,7 +1476,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
14731476
})
14741477
});
14751478

1476-
let debugging_opts = build_debugging_options(matches, error_format);
1479+
let mut debugging_opts = build_debugging_options(matches, error_format);
14771480

14781481
if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
14791482
early_error(ErrorOutputType::Json(false),
@@ -1579,6 +1582,10 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
15791582
prints.push(PrintRequest::CodeModels);
15801583
cg.code_model = None;
15811584
}
1585+
if debugging_opts.tls_model.as_ref().map_or(false, |s| s == "help") {
1586+
prints.push(PrintRequest::TlsModels);
1587+
debugging_opts.tls_model = None;
1588+
}
15821589

15831590
let cg = cg;
15841591

@@ -1678,6 +1685,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
16781685
"target-features" => PrintRequest::TargetFeatures,
16791686
"relocation-models" => PrintRequest::RelocationModels,
16801687
"code-models" => PrintRequest::CodeModels,
1688+
"tls-models" => PrintRequest::TlsModels,
16811689
"native-static-libs" => PrintRequest::NativeStaticLibs,
16821690
"target-spec-json" => {
16831691
if nightly_options::is_unstable_enabled(matches) {
@@ -2520,6 +2528,10 @@ mod tests {
25202528
opts.cg.code_model = Some(String::from("code model"));
25212529
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
25222530

2531+
opts = reference.clone();
2532+
opts.debugging_opts.tls_model = Some(String::from("tls model"));
2533+
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2534+
25232535
opts = reference.clone();
25242536
opts.cg.metadata = vec![String::from("A"), String::from("B")];
25252537
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());

src/librustc_back/target/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ pub struct TargetOptions {
311311
pub relocation_model: String,
312312
/// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default".
313313
pub code_model: String,
314+
/// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec"
315+
/// and "local-exec". This is similar to the -ftls-model option in GCC/Clang.
316+
pub tls_model: String,
314317
/// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
315318
pub disable_redzone: bool,
316319
/// Eliminate frame pointers from stack frames if possible. Defaults to true.
@@ -450,6 +453,7 @@ impl Default for TargetOptions {
450453
executables: false,
451454
relocation_model: "pic".to_string(),
452455
code_model: "default".to_string(),
456+
tls_model: "global-dynamic".to_string(),
453457
disable_redzone: false,
454458
eliminate_frame_pointer: true,
455459
function_sections: true,
@@ -696,6 +700,7 @@ impl Target {
696700
key!(executables, bool);
697701
key!(relocation_model);
698702
key!(code_model);
703+
key!(tls_model);
699704
key!(disable_redzone, bool);
700705
key!(eliminate_frame_pointer, bool);
701706
key!(function_sections, bool);
@@ -888,6 +893,7 @@ impl ToJson for Target {
888893
target_option_val!(executables);
889894
target_option_val!(relocation_model);
890895
target_option_val!(code_model);
896+
target_option_val!(tls_model);
891897
target_option_val!(disable_redzone);
892898
target_option_val!(eliminate_frame_pointer);
893899
target_option_val!(function_sections);

src/librustc_driver/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ mod rustc_trans {
177177
pub mod write {
178178
pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = [];
179179
pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = [];
180+
pub const TLS_MODEL_ARGS: [(&'static str, ()); 0] = [];
180181
}
181182
}
182183
}
@@ -797,6 +798,13 @@ impl RustcDefaultCalls {
797798
}
798799
println!("");
799800
}
801+
PrintRequest::TlsModels => {
802+
println!("Available TLS models:");
803+
for &(name, _) in rustc_trans::back::write::TLS_MODEL_ARGS.iter(){
804+
println!(" {}", name);
805+
}
806+
println!("");
807+
}
800808
PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => {
801809
rustc_trans::print(*req, sess);
802810
}

src/librustc_llvm/ffi.rs

+12
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,17 @@ pub struct ThinLTOModule {
359359
pub len: usize,
360360
}
361361

362+
/// LLVMThreadLocalMode
363+
#[derive(Copy, Clone)]
364+
#[repr(C)]
365+
pub enum ThreadLocalMode {
366+
NotThreadLocal,
367+
GeneralDynamic,
368+
LocalDynamic,
369+
InitialExec,
370+
LocalExec
371+
}
372+
362373
// Opaque pointer types
363374
#[allow(missing_copy_implementations)]
364375
pub enum Module_opaque {}
@@ -709,6 +720,7 @@ extern "C" {
709720
pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef;
710721
pub fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef);
711722
pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool);
723+
pub fn LLVMSetThreadLocalMode(GlobalVar: ValueRef, Mode: ThreadLocalMode);
712724
pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool;
713725
pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool);
714726
pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef;

src/librustc_llvm/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) {
172172
LLVMSetThreadLocal(global, is_thread_local as Bool);
173173
}
174174
}
175+
pub fn set_thread_local_mode(global: ValueRef, mode: ThreadLocalMode) {
176+
unsafe {
177+
LLVMSetThreadLocalMode(global, mode);
178+
}
179+
}
175180

176181
impl Attribute {
177182
pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {

src/librustc_trans/back/write.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [
7676
("large", llvm::CodeModel::Large),
7777
];
7878

79+
pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [
80+
("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
81+
("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
82+
("initial-exec", llvm::ThreadLocalMode::InitialExec),
83+
("local-exec", llvm::ThreadLocalMode::LocalExec),
84+
];
85+
7986
pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
8087
match llvm::last_error() {
8188
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
@@ -173,9 +180,7 @@ pub fn target_machine_factory(sess: &Session)
173180
Some(x) => x.1,
174181
_ => {
175182
sess.err(&format!("{:?} is not a valid code model",
176-
sess.opts
177-
.cg
178-
.code_model));
183+
code_model_arg));
179184
sess.abort_if_errors();
180185
bug!();
181186
}

src/librustc_trans/consts.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
196196

197197
for attr in attrs {
198198
if attr.check_name("thread_local") {
199-
llvm::set_thread_local(g, true);
199+
llvm::set_thread_local_mode(g, ccx.tls_model());
200200
}
201201
}
202202

@@ -215,7 +215,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
215215
// symbol and another one doesn't.
216216
for attr in ccx.tcx().get_attrs(def_id).iter() {
217217
if attr.check_name("thread_local") {
218-
llvm::set_thread_local(g, true);
218+
llvm::set_thread_local_mode(g, ccx.tls_model());
219219
}
220220
}
221221
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>,
305305

306306
debuginfo::create_global_var_metadata(ccx, id, g);
307307

308-
if attr::contains_name(attrs,
309-
"thread_local") {
310-
llvm::set_thread_local(g, true);
308+
if attr::contains_name(attrs, "thread_local") {
309+
llvm::set_thread_local_mode(g, ccx.tls_model());
311310
}
312311

313312
base::set_link_section(ccx, g, attrs);

src/librustc_trans/context.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
5252
tcx: TyCtxt<'a, 'tcx, 'tcx>,
5353
check_overflow: bool,
5454
use_dll_storage_attrs: bool,
55+
tls_model: llvm::ThreadLocalMode,
5556
}
5657

5758
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@@ -159,9 +160,25 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode {
159160
Some(x) => x.1,
160161
_ => {
161162
sess.err(&format!("{:?} is not a valid relocation mode",
162-
sess.opts
163-
.cg
164-
.code_model));
163+
reloc_model_arg));
164+
sess.abort_if_errors();
165+
bug!();
166+
}
167+
}
168+
}
169+
170+
fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode {
171+
let tls_model_arg = match sess.opts.debugging_opts.tls_model {
172+
Some(ref s) => &s[..],
173+
None => &sess.target.target.options.tls_model[..],
174+
};
175+
176+
match ::back::write::TLS_MODEL_ARGS.iter().find(
177+
|&&arg| arg.0 == tls_model_arg) {
178+
Some(x) => x.1,
179+
_ => {
180+
sess.err(&format!("{:?} is not a valid TLS model",
181+
tls_model_arg));
165182
sess.abort_if_errors();
166183
bug!();
167184
}
@@ -283,10 +300,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
283300

284301
let check_overflow = tcx.sess.overflow_checks();
285302

303+
let tls_model = get_tls_model(&tcx.sess);
304+
286305
SharedCrateContext {
287306
tcx,
288307
check_overflow,
289308
use_dll_storage_attrs,
309+
tls_model,
290310
}
291311
}
292312

@@ -528,6 +548,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
528548
self.shared.use_dll_storage_attrs()
529549
}
530550

551+
pub fn tls_model(&self) -> llvm::ThreadLocalMode {
552+
self.shared.tls_model
553+
}
554+
531555
/// Generate a new symbol name with the given prefix. This symbol name must
532556
/// only be used for definitions with `internal` or `private` linkage.
533557
pub fn generate_local_symbol_name(&self, prefix: &str) -> String {

0 commit comments

Comments
 (0)