]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/llvm_util.rs
9fcc33d82cfa4d1ea751db891308dc3680eda081
[rust.git] / src / librustc_codegen_llvm / llvm_util.rs
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;
16 use libc::c_int;
17 use std::ffi::CString;
18 use syntax::feature_gate::UnstableFeatures;
19
20 use std::str;
21 use std::slice;
22 use std::sync::atomic::{AtomicBool, Ordering};
23 use std::sync::Once;
24
25 static POISONED: AtomicBool = AtomicBool::new(false);
26 static INIT: Once = Once::new();
27
28 pub(crate) fn init(sess: &Session) {
29     unsafe {
30         // Before we touch LLVM, make sure that multithreading is enabled.
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
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
54 unsafe fn configure_llvm(sess: &Session) {
55     let mut llvm_c_strs = Vec::new();
56     let mut llvm_args = Vec::new();
57
58     {
59         let mut add = |arg: &str| {
60             let s = CString::new(arg).unwrap();
61             llvm_args.push(s.as_ptr());
62             llvm_c_strs.push(s);
63         };
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");
69         }
70
71         for arg in &sess.opts.cg.llvm_args {
72             add(&(*arg));
73         }
74     }
75
76     llvm::LLVMInitializePasses();
77
78     ::rustc_llvm::initialize_available_targets();
79
80     llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
81                                  llvm_args.as_ptr());
82 }
83
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.
87
88 const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
89     ("mclass", Some("arm_target_feature")),
90     ("rclass", Some("arm_target_feature")),
91     ("dsp", Some("arm_target_feature")),
92     ("neon", Some("arm_target_feature")),
93     ("v7", Some("arm_target_feature")),
94     ("vfp2", Some("arm_target_feature")),
95     ("vfp3", Some("arm_target_feature")),
96     ("vfp4", Some("arm_target_feature")),
97 ];
98
99 const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
100     ("fp", Some("aarch64_target_feature")),
101     ("neon", Some("aarch64_target_feature")),
102     ("sve", Some("aarch64_target_feature")),
103     ("crc", Some("aarch64_target_feature")),
104     ("crypto", Some("aarch64_target_feature")),
105     ("ras", Some("aarch64_target_feature")),
106     ("lse", Some("aarch64_target_feature")),
107     ("rdm", Some("aarch64_target_feature")),
108     ("fp16", Some("aarch64_target_feature")),
109     ("rcpc", Some("aarch64_target_feature")),
110     ("dotprod", Some("aarch64_target_feature")),
111     ("v8.1a", Some("aarch64_target_feature")),
112     ("v8.2a", Some("aarch64_target_feature")),
113     ("v8.3a", Some("aarch64_target_feature")),
114 ];
115
116 const X86_WHITELIST: &[(&str, Option<&str>)] = &[
117     ("aes", None),
118     ("avx", None),
119     ("avx2", None),
120     ("avx512bw", Some("avx512_target_feature")),
121     ("avx512cd", Some("avx512_target_feature")),
122     ("avx512dq", Some("avx512_target_feature")),
123     ("avx512er", Some("avx512_target_feature")),
124     ("avx512f", Some("avx512_target_feature")),
125     ("avx512ifma", Some("avx512_target_feature")),
126     ("avx512pf", Some("avx512_target_feature")),
127     ("avx512vbmi", Some("avx512_target_feature")),
128     ("avx512vl", Some("avx512_target_feature")),
129     ("avx512vpopcntdq", Some("avx512_target_feature")),
130     ("bmi1", None),
131     ("bmi2", None),
132     ("fma", None),
133     ("fxsr", None),
134     ("lzcnt", None),
135     ("mmx", Some("mmx_target_feature")),
136     ("pclmulqdq", None),
137     ("popcnt", None),
138     ("rdrand", None),
139     ("rdseed", None),
140     ("sha", None),
141     ("sse", None),
142     ("sse2", None),
143     ("sse3", None),
144     ("sse4.1", None),
145     ("sse4.2", None),
146     ("sse4a", Some("sse4a_target_feature")),
147     ("ssse3", None),
148     ("tbm", Some("tbm_target_feature")),
149     ("xsave", None),
150     ("xsavec", None),
151     ("xsaveopt", None),
152     ("xsaves", None),
153 ];
154
155 const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
156     ("hvx", Some("hexagon_target_feature")),
157     ("hvx-double", Some("hexagon_target_feature")),
158 ];
159
160 const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
161     ("altivec", Some("powerpc_target_feature")),
162     ("power8-altivec", Some("powerpc_target_feature")),
163     ("power9-altivec", Some("powerpc_target_feature")),
164     ("power8-vector", Some("powerpc_target_feature")),
165     ("power9-vector", Some("powerpc_target_feature")),
166     ("vsx", Some("powerpc_target_feature")),
167 ];
168
169 const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
170     ("fp64", Some("mips_target_feature")),
171     ("msa", Some("mips_target_feature")),
172 ];
173
174 const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
175     ("simd128", Some("wasm_target_feature")),
176 ];
177
178 /// When rustdoc is running, provide a list of all known features so that all their respective
179 /// primtives may be documented.
180 ///
181 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
182 /// iterator!
183 pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
184     ARM_WHITELIST.iter().cloned()
185         .chain(AARCH64_WHITELIST.iter().cloned())
186         .chain(X86_WHITELIST.iter().cloned())
187         .chain(HEXAGON_WHITELIST.iter().cloned())
188         .chain(POWERPC_WHITELIST.iter().cloned())
189         .chain(MIPS_WHITELIST.iter().cloned())
190         .chain(WASM_WHITELIST.iter().cloned())
191 }
192
193 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
194     let arch = if sess.target.target.arch == "x86_64" {
195         "x86"
196     } else {
197         &*sess.target.target.arch
198     };
199     match (arch, s) {
200         ("x86", "pclmulqdq") => "pclmul",
201         ("x86", "rdrand") => "rdrnd",
202         ("x86", "bmi1") => "bmi",
203         ("aarch64", "fp") => "fp-armv8",
204         ("aarch64", "fp16") => "fullfp16",
205         (_, s) => s,
206     }
207 }
208
209 pub fn target_features(sess: &Session) -> Vec<Symbol> {
210     let target_machine = create_target_machine(sess, true);
211     target_feature_whitelist(sess)
212         .iter()
213         .filter_map(|&(feature, gate)| {
214             if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
215                 Some(feature)
216             } else {
217                 None
218             }
219         })
220         .filter(|feature| {
221             let llvm_feature = to_llvm_feature(sess, feature);
222             let cstr = CString::new(llvm_feature).unwrap();
223             unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
224         })
225         .map(|feature| Symbol::intern(feature)).collect()
226 }
227
228 pub fn target_feature_whitelist(sess: &Session)
229     -> &'static [(&'static str, Option<&'static str>)]
230 {
231     match &*sess.target.target.arch {
232         "arm" => ARM_WHITELIST,
233         "aarch64" => AARCH64_WHITELIST,
234         "x86" | "x86_64" => X86_WHITELIST,
235         "hexagon" => HEXAGON_WHITELIST,
236         "mips" | "mips64" => MIPS_WHITELIST,
237         "powerpc" | "powerpc64" => POWERPC_WHITELIST,
238         "wasm32" => WASM_WHITELIST,
239         _ => &[],
240     }
241 }
242
243 pub fn print_version() {
244     // Can be called without initializing LLVM
245     unsafe {
246         println!("LLVM version: {}.{}",
247                  llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
248     }
249 }
250
251 pub fn print_passes() {
252     // Can be called without initializing LLVM
253     unsafe { llvm::LLVMRustPrintPasses(); }
254 }
255
256 pub(crate) fn print(req: PrintRequest, sess: &Session) {
257     require_inited();
258     let tm = create_target_machine(sess, true);
259     unsafe {
260         match req {
261             PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
262             PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
263             _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
264         }
265     }
266 }
267
268 pub fn target_cpu(sess: &Session) -> &str {
269     let name = match sess.opts.cg.target_cpu {
270         Some(ref s) => &**s,
271         None => &*sess.target.target.options.cpu
272     };
273     if name != "native" {
274         return name
275     }
276
277     unsafe {
278         let mut len = 0;
279         let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
280         str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
281     }
282 }