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.
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.
11 use syntax_pos::symbol::Symbol;
12 use back::write::create_target_machine;
14 use rustc::session::Session;
15 use rustc::session::config::PrintRequest;
17 use std::ffi::CString;
18 use syntax::feature_gate::UnstableFeatures;
22 use std::sync::atomic::{AtomicBool, Ordering};
25 static POISONED: AtomicBool = AtomicBool::new(false);
26 static INIT: Once = Once::new();
28 pub(crate) fn init(sess: &Session) {
30 // Before we touch LLVM, make sure that multithreading is enabled.
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);
41 if POISONED.load(Ordering::SeqCst) {
42 bug!("couldn't enable multi-threaded LLVM");
48 INIT.call_once(|| bug!("llvm is not initialized"));
49 if POISONED.load(Ordering::SeqCst) {
50 bug!("couldn't enable multi-threaded LLVM");
54 unsafe fn configure_llvm(sess: &Session) {
55 let mut llvm_c_strs = Vec::new();
56 let mut llvm_args = Vec::new();
59 let mut add = |arg: &str| {
60 let s = CString::new(arg).unwrap();
61 llvm_args.push(s.as_ptr());
64 add("rustc"); // fake program name
65 if sess.time_llvm_passes() { add("-time-passes"); }
66 if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
67 if sess.opts.debugging_opts.disable_instrumentation_preinliner {
68 add("-disable-preinline");
71 for arg in &sess.opts.cg.llvm_args {
76 llvm::LLVMInitializePasses();
78 ::rustc_llvm::initialize_available_targets();
80 llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
84 // WARNING: the features after applying `to_llvm_feature` must be known
85 // to LLVM or the feature detection code will walk past the end of the feature
86 // array, leading to crashes.
88 const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
89 ("aclass", Some("arm_target_feature")),
90 ("mclass", Some("arm_target_feature")),
91 ("rclass", Some("arm_target_feature")),
92 ("dsp", Some("arm_target_feature")),
93 ("neon", Some("arm_target_feature")),
94 ("v5te", Some("arm_target_feature")),
95 ("v6k", Some("arm_target_feature")),
96 ("v6t2", Some("arm_target_feature")),
97 ("v7", Some("arm_target_feature")),
98 ("vfp2", Some("arm_target_feature")),
99 ("vfp3", Some("arm_target_feature")),
100 ("vfp4", Some("arm_target_feature")),
103 const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
104 ("fp", Some("aarch64_target_feature")),
105 ("neon", Some("aarch64_target_feature")),
106 ("sve", Some("aarch64_target_feature")),
107 ("crc", Some("aarch64_target_feature")),
108 ("crypto", Some("aarch64_target_feature")),
109 ("ras", Some("aarch64_target_feature")),
110 ("lse", Some("aarch64_target_feature")),
111 ("rdm", Some("aarch64_target_feature")),
112 ("fp16", Some("aarch64_target_feature")),
113 ("rcpc", Some("aarch64_target_feature")),
114 ("dotprod", Some("aarch64_target_feature")),
115 ("v8.1a", Some("aarch64_target_feature")),
116 ("v8.2a", Some("aarch64_target_feature")),
117 ("v8.3a", Some("aarch64_target_feature")),
120 const X86_WHITELIST: &[(&str, Option<&str>)] = &[
124 ("avx512bw", Some("avx512_target_feature")),
125 ("avx512cd", Some("avx512_target_feature")),
126 ("avx512dq", Some("avx512_target_feature")),
127 ("avx512er", Some("avx512_target_feature")),
128 ("avx512f", Some("avx512_target_feature")),
129 ("avx512ifma", Some("avx512_target_feature")),
130 ("avx512pf", Some("avx512_target_feature")),
131 ("avx512vbmi", Some("avx512_target_feature")),
132 ("avx512vl", Some("avx512_target_feature")),
133 ("avx512vpopcntdq", Some("avx512_target_feature")),
139 ("mmx", Some("mmx_target_feature")),
150 ("sse4a", Some("sse4a_target_feature")),
152 ("tbm", Some("tbm_target_feature")),
159 const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
160 ("hvx", Some("hexagon_target_feature")),
161 ("hvx-double", Some("hexagon_target_feature")),
164 const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
165 ("altivec", Some("powerpc_target_feature")),
166 ("power8-altivec", Some("powerpc_target_feature")),
167 ("power9-altivec", Some("powerpc_target_feature")),
168 ("power8-vector", Some("powerpc_target_feature")),
169 ("power9-vector", Some("powerpc_target_feature")),
170 ("vsx", Some("powerpc_target_feature")),
173 const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
174 ("fp64", Some("mips_target_feature")),
175 ("msa", Some("mips_target_feature")),
178 const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
179 ("simd128", Some("wasm_target_feature")),
180 ("atomics", Some("wasm_target_feature")),
183 /// When rustdoc is running, provide a list of all known features so that all their respective
184 /// primtives may be documented.
186 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
188 pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
189 ARM_WHITELIST.iter().cloned()
190 .chain(AARCH64_WHITELIST.iter().cloned())
191 .chain(X86_WHITELIST.iter().cloned())
192 .chain(HEXAGON_WHITELIST.iter().cloned())
193 .chain(POWERPC_WHITELIST.iter().cloned())
194 .chain(MIPS_WHITELIST.iter().cloned())
195 .chain(WASM_WHITELIST.iter().cloned())
198 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
199 let arch = if sess.target.target.arch == "x86_64" {
202 &*sess.target.target.arch
205 ("x86", "pclmulqdq") => "pclmul",
206 ("x86", "rdrand") => "rdrnd",
207 ("x86", "bmi1") => "bmi",
208 ("aarch64", "fp") => "fp-armv8",
209 ("aarch64", "fp16") => "fullfp16",
214 pub fn target_features(sess: &Session) -> Vec<Symbol> {
215 let target_machine = create_target_machine(sess, true);
216 target_feature_whitelist(sess)
218 .filter_map(|&(feature, gate)| {
219 if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
226 let llvm_feature = to_llvm_feature(sess, feature);
227 let cstr = CString::new(llvm_feature).unwrap();
228 unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
230 .map(|feature| Symbol::intern(feature)).collect()
233 pub fn target_feature_whitelist(sess: &Session)
234 -> &'static [(&'static str, Option<&'static str>)]
236 match &*sess.target.target.arch {
237 "arm" => ARM_WHITELIST,
238 "aarch64" => AARCH64_WHITELIST,
239 "x86" | "x86_64" => X86_WHITELIST,
240 "hexagon" => HEXAGON_WHITELIST,
241 "mips" | "mips64" => MIPS_WHITELIST,
242 "powerpc" | "powerpc64" => POWERPC_WHITELIST,
243 "wasm32" => WASM_WHITELIST,
248 pub fn print_version() {
249 // Can be called without initializing LLVM
251 println!("LLVM version: {}.{}",
252 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
256 pub fn print_passes() {
257 // Can be called without initializing LLVM
258 unsafe { llvm::LLVMRustPrintPasses(); }
261 pub(crate) fn print(req: PrintRequest, sess: &Session) {
263 let tm = create_target_machine(sess, true);
266 PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
267 PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
268 _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
273 pub fn target_cpu(sess: &Session) -> &str {
274 let name = match sess.opts.cg.target_cpu {
276 None => &*sess.target.target.options.cpu
278 if name != "native" {
284 let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
285 str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()