]> git.proxmox.com Git - rustc.git/blame - src/librustc_codegen_llvm/llvm_util.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc_codegen_llvm / llvm_util.rs
CommitLineData
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
11use syntax_pos::symbol::Symbol;
12use back::write::create_target_machine;
13use llvm;
14use rustc::session::Session;
15use rustc::session::config::PrintRequest;
2c00a5a8 16use libc::c_int;
0531ce1d 17use std::ffi::CString;
83c7162d 18use syntax::feature_gate::UnstableFeatures;
7cac9316 19
b7449926
XL
20use std::str;
21use std::slice;
7cac9316
XL
22use std::sync::atomic::{AtomicBool, Ordering};
23use std::sync::Once;
24
2c00a5a8
XL
25static POISONED: AtomicBool = AtomicBool::new(false);
26static INIT: Once = Once::new();
27
28pub(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
47fn 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 54unsafe 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 91const 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
106const 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
123const 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
162const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
163 ("hvx", Some("hexagon_target_feature")),
164 ("hvx-double", Some("hexagon_target_feature")),
165];
166
167const 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
176const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
177 ("fp64", Some("mips_target_feature")),
178 ("msa", Some("mips_target_feature")),
179];
0531ce1d 180
b7449926
XL
181const 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 191pub 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
201pub 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 217pub 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
236pub 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
251pub 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
259pub fn print_passes() {
2c00a5a8 260 // Can be called without initializing LLVM
7cac9316
XL
261 unsafe { llvm::LLVMRustPrintPasses(); }
262}
263
2c00a5a8
XL
264pub(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
276pub 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}