]>
Commit | Line | Data |
---|---|---|
7cac9316 XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use syntax_pos::symbol::Symbol; | |
12 | use back::write::create_target_machine; | |
13 | use llvm; | |
14 | use rustc::session::Session; | |
15 | use rustc::session::config::PrintRequest; | |
2c00a5a8 | 16 | use libc::c_int; |
0531ce1d | 17 | use std::ffi::CString; |
83c7162d | 18 | use syntax::feature_gate::UnstableFeatures; |
7cac9316 | 19 | |
b7449926 XL |
20 | use std::str; |
21 | use std::slice; | |
7cac9316 XL |
22 | use std::sync::atomic::{AtomicBool, Ordering}; |
23 | use std::sync::Once; | |
24 | ||
2c00a5a8 XL |
25 | static POISONED: AtomicBool = AtomicBool::new(false); |
26 | static INIT: Once = Once::new(); | |
27 | ||
28 | pub(crate) fn init(sess: &Session) { | |
7cac9316 XL |
29 | unsafe { |
30 | // Before we touch LLVM, make sure that multithreading is enabled. | |
7cac9316 XL |
31 | INIT.call_once(|| { |
32 | if llvm::LLVMStartMultithreaded() != 1 { | |
33 | // use an extra bool to make sure that all future usage of LLVM | |
34 | // cannot proceed despite the Once not running more than once. | |
35 | POISONED.store(true, Ordering::SeqCst); | |
36 | } | |
37 | ||
38 | configure_llvm(sess); | |
39 | }); | |
40 | ||
41 | if POISONED.load(Ordering::SeqCst) { | |
42 | bug!("couldn't enable multi-threaded LLVM"); | |
43 | } | |
44 | } | |
45 | } | |
46 | ||
2c00a5a8 XL |
47 | fn require_inited() { |
48 | INIT.call_once(|| bug!("llvm is not initialized")); | |
49 | if POISONED.load(Ordering::SeqCst) { | |
50 | bug!("couldn't enable multi-threaded LLVM"); | |
51 | } | |
52 | } | |
53 | ||
7cac9316 | 54 | unsafe fn configure_llvm(sess: &Session) { |
0bf4aa26 XL |
55 | let n_args = sess.opts.cg.llvm_args.len(); |
56 | let mut llvm_c_strs = Vec::with_capacity(n_args + 1); | |
57 | let mut llvm_args = Vec::with_capacity(n_args + 1); | |
58 | ||
59 | llvm::LLVMRustInstallFatalErrorHandler(); | |
7cac9316 XL |
60 | |
61 | { | |
62 | let mut add = |arg: &str| { | |
63 | let s = CString::new(arg).unwrap(); | |
64 | llvm_args.push(s.as_ptr()); | |
65 | llvm_c_strs.push(s); | |
66 | }; | |
67 | add("rustc"); // fake program name | |
68 | if sess.time_llvm_passes() { add("-time-passes"); } | |
69 | if sess.print_llvm_passes() { add("-debug-pass=Structure"); } | |
0531ce1d XL |
70 | if sess.opts.debugging_opts.disable_instrumentation_preinliner { |
71 | add("-disable-preinline"); | |
72 | } | |
7cac9316 XL |
73 | |
74 | for arg in &sess.opts.cg.llvm_args { | |
75 | add(&(*arg)); | |
76 | } | |
77 | } | |
78 | ||
79 | llvm::LLVMInitializePasses(); | |
80 | ||
b7449926 | 81 | ::rustc_llvm::initialize_available_targets(); |
7cac9316 XL |
82 | |
83 | llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, | |
84 | llvm_args.as_ptr()); | |
85 | } | |
86 | ||
0531ce1d XL |
87 | // WARNING: the features after applying `to_llvm_feature` must be known |
88 | // to LLVM or the feature detection code will walk past the end of the feature | |
89 | // array, leading to crashes. | |
90 | ||
83c7162d | 91 | const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ |
b7449926 | 92 | ("aclass", Some("arm_target_feature")), |
8faf50e0 XL |
93 | ("mclass", Some("arm_target_feature")), |
94 | ("rclass", Some("arm_target_feature")), | |
95 | ("dsp", Some("arm_target_feature")), | |
83c7162d | 96 | ("neon", Some("arm_target_feature")), |
b7449926 XL |
97 | ("v5te", Some("arm_target_feature")), |
98 | ("v6k", Some("arm_target_feature")), | |
99 | ("v6t2", Some("arm_target_feature")), | |
83c7162d XL |
100 | ("v7", Some("arm_target_feature")), |
101 | ("vfp2", Some("arm_target_feature")), | |
102 | ("vfp3", Some("arm_target_feature")), | |
103 | ("vfp4", Some("arm_target_feature")), | |
104 | ]; | |
105 | ||
106 | const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[ | |
107 | ("fp", Some("aarch64_target_feature")), | |
108 | ("neon", Some("aarch64_target_feature")), | |
109 | ("sve", Some("aarch64_target_feature")), | |
110 | ("crc", Some("aarch64_target_feature")), | |
111 | ("crypto", Some("aarch64_target_feature")), | |
112 | ("ras", Some("aarch64_target_feature")), | |
113 | ("lse", Some("aarch64_target_feature")), | |
114 | ("rdm", Some("aarch64_target_feature")), | |
115 | ("fp16", Some("aarch64_target_feature")), | |
116 | ("rcpc", Some("aarch64_target_feature")), | |
117 | ("dotprod", Some("aarch64_target_feature")), | |
118 | ("v8.1a", Some("aarch64_target_feature")), | |
119 | ("v8.2a", Some("aarch64_target_feature")), | |
120 | ("v8.3a", Some("aarch64_target_feature")), | |
121 | ]; | |
122 | ||
123 | const X86_WHITELIST: &[(&str, Option<&str>)] = &[ | |
124 | ("aes", None), | |
125 | ("avx", None), | |
126 | ("avx2", None), | |
127 | ("avx512bw", Some("avx512_target_feature")), | |
128 | ("avx512cd", Some("avx512_target_feature")), | |
129 | ("avx512dq", Some("avx512_target_feature")), | |
130 | ("avx512er", Some("avx512_target_feature")), | |
131 | ("avx512f", Some("avx512_target_feature")), | |
132 | ("avx512ifma", Some("avx512_target_feature")), | |
133 | ("avx512pf", Some("avx512_target_feature")), | |
134 | ("avx512vbmi", Some("avx512_target_feature")), | |
135 | ("avx512vl", Some("avx512_target_feature")), | |
136 | ("avx512vpopcntdq", Some("avx512_target_feature")), | |
137 | ("bmi1", None), | |
138 | ("bmi2", None), | |
139 | ("fma", None), | |
140 | ("fxsr", None), | |
141 | ("lzcnt", None), | |
142 | ("mmx", Some("mmx_target_feature")), | |
143 | ("pclmulqdq", None), | |
144 | ("popcnt", None), | |
145 | ("rdrand", None), | |
146 | ("rdseed", None), | |
147 | ("sha", None), | |
148 | ("sse", None), | |
149 | ("sse2", None), | |
150 | ("sse3", None), | |
151 | ("sse4.1", None), | |
152 | ("sse4.2", None), | |
153 | ("sse4a", Some("sse4a_target_feature")), | |
154 | ("ssse3", None), | |
155 | ("tbm", Some("tbm_target_feature")), | |
156 | ("xsave", None), | |
157 | ("xsavec", None), | |
158 | ("xsaveopt", None), | |
159 | ("xsaves", None), | |
160 | ]; | |
161 | ||
162 | const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[ | |
163 | ("hvx", Some("hexagon_target_feature")), | |
164 | ("hvx-double", Some("hexagon_target_feature")), | |
165 | ]; | |
166 | ||
167 | const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[ | |
168 | ("altivec", Some("powerpc_target_feature")), | |
169 | ("power8-altivec", Some("powerpc_target_feature")), | |
170 | ("power9-altivec", Some("powerpc_target_feature")), | |
171 | ("power8-vector", Some("powerpc_target_feature")), | |
172 | ("power9-vector", Some("powerpc_target_feature")), | |
173 | ("vsx", Some("powerpc_target_feature")), | |
174 | ]; | |
175 | ||
176 | const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ | |
177 | ("fp64", Some("mips_target_feature")), | |
178 | ("msa", Some("mips_target_feature")), | |
179 | ]; | |
0531ce1d | 180 | |
b7449926 XL |
181 | const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ |
182 | ("simd128", Some("wasm_target_feature")), | |
183 | ("atomics", Some("wasm_target_feature")), | |
184 | ]; | |
185 | ||
0531ce1d XL |
186 | /// When rustdoc is running, provide a list of all known features so that all their respective |
187 | /// primtives may be documented. | |
188 | /// | |
189 | /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this | |
190 | /// iterator! | |
83c7162d | 191 | pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> { |
0531ce1d XL |
192 | ARM_WHITELIST.iter().cloned() |
193 | .chain(AARCH64_WHITELIST.iter().cloned()) | |
194 | .chain(X86_WHITELIST.iter().cloned()) | |
195 | .chain(HEXAGON_WHITELIST.iter().cloned()) | |
196 | .chain(POWERPC_WHITELIST.iter().cloned()) | |
197 | .chain(MIPS_WHITELIST.iter().cloned()) | |
b7449926 | 198 | .chain(WASM_WHITELIST.iter().cloned()) |
0531ce1d | 199 | } |
3b2f2976 | 200 | |
0531ce1d XL |
201 | pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { |
202 | let arch = if sess.target.target.arch == "x86_64" { | |
203 | "x86" | |
204 | } else { | |
205 | &*sess.target.target.arch | |
206 | }; | |
207 | match (arch, s) { | |
208 | ("x86", "pclmulqdq") => "pclmul", | |
209 | ("x86", "rdrand") => "rdrnd", | |
210 | ("x86", "bmi1") => "bmi", | |
83c7162d | 211 | ("aarch64", "fp") => "fp-armv8", |
0531ce1d XL |
212 | ("aarch64", "fp16") => "fullfp16", |
213 | (_, s) => s, | |
214 | } | |
215 | } | |
ff7c6d11 | 216 | |
7cac9316 | 217 | pub fn target_features(sess: &Session) -> Vec<Symbol> { |
83c7162d | 218 | let target_machine = create_target_machine(sess, true); |
0531ce1d XL |
219 | target_feature_whitelist(sess) |
220 | .iter() | |
83c7162d XL |
221 | .filter_map(|&(feature, gate)| { |
222 | if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { | |
223 | Some(feature) | |
224 | } else { | |
225 | None | |
226 | } | |
227 | }) | |
0531ce1d XL |
228 | .filter(|feature| { |
229 | let llvm_feature = to_llvm_feature(sess, feature); | |
230 | let cstr = CString::new(llvm_feature).unwrap(); | |
231 | unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } | |
232 | }) | |
233 | .map(|feature| Symbol::intern(feature)).collect() | |
2c00a5a8 | 234 | } |
7cac9316 | 235 | |
83c7162d XL |
236 | pub fn target_feature_whitelist(sess: &Session) |
237 | -> &'static [(&'static str, Option<&'static str>)] | |
238 | { | |
0531ce1d | 239 | match &*sess.target.target.arch { |
7cac9316 | 240 | "arm" => ARM_WHITELIST, |
abe05a73 | 241 | "aarch64" => AARCH64_WHITELIST, |
7cac9316 XL |
242 | "x86" | "x86_64" => X86_WHITELIST, |
243 | "hexagon" => HEXAGON_WHITELIST, | |
ff7c6d11 | 244 | "mips" | "mips64" => MIPS_WHITELIST, |
3b2f2976 | 245 | "powerpc" | "powerpc64" => POWERPC_WHITELIST, |
b7449926 | 246 | "wasm32" => WASM_WHITELIST, |
7cac9316 | 247 | _ => &[], |
0531ce1d | 248 | } |
7cac9316 XL |
249 | } |
250 | ||
251 | pub fn print_version() { | |
2c00a5a8 | 252 | // Can be called without initializing LLVM |
7cac9316 XL |
253 | unsafe { |
254 | println!("LLVM version: {}.{}", | |
255 | llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor()); | |
256 | } | |
257 | } | |
258 | ||
259 | pub fn print_passes() { | |
2c00a5a8 | 260 | // Can be called without initializing LLVM |
7cac9316 XL |
261 | unsafe { llvm::LLVMRustPrintPasses(); } |
262 | } | |
263 | ||
2c00a5a8 XL |
264 | pub(crate) fn print(req: PrintRequest, sess: &Session) { |
265 | require_inited(); | |
83c7162d | 266 | let tm = create_target_machine(sess, true); |
7cac9316 XL |
267 | unsafe { |
268 | match req { | |
269 | PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), | |
270 | PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm), | |
94b46f34 | 271 | _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), |
7cac9316 XL |
272 | } |
273 | } | |
274 | } | |
b7449926 XL |
275 | |
276 | pub fn target_cpu(sess: &Session) -> &str { | |
277 | let name = match sess.opts.cg.target_cpu { | |
278 | Some(ref s) => &**s, | |
279 | None => &*sess.target.target.options.cpu | |
280 | }; | |
281 | if name != "native" { | |
282 | return name | |
283 | } | |
284 | ||
285 | unsafe { | |
286 | let mut len = 0; | |
287 | let ptr = llvm::LLVMRustGetHostCPUName(&mut len); | |
288 | str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap() | |
289 | } | |
290 | } |