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