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