]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/llvm_util.rs
Auto merge of #58649 - pnkfelix:issue-57464-avoid-ice-when-region-sneaks-into-impl...
[rust.git] / src / librustc_codegen_llvm / llvm_util.rs
1 use crate::back::write::create_informational_target_machine;
2 use crate::llvm;
3 use syntax_pos::symbol::Symbol;
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     ("v6", Some("arm_target_feature")),
104     ("v6k", Some("arm_target_feature")),
105     ("v6t2", Some("arm_target_feature")),
106     ("v7", Some("arm_target_feature")),
107     ("v8", Some("arm_target_feature")),
108     ("vfp2", Some("arm_target_feature")),
109     ("vfp3", Some("arm_target_feature")),
110     ("vfp4", Some("arm_target_feature")),
111 ];
112
113 const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
114     ("fp", Some("aarch64_target_feature")),
115     ("neon", Some("aarch64_target_feature")),
116     ("sve", Some("aarch64_target_feature")),
117     ("crc", Some("aarch64_target_feature")),
118     ("crypto", Some("aarch64_target_feature")),
119     ("ras", Some("aarch64_target_feature")),
120     ("lse", Some("aarch64_target_feature")),
121     ("rdm", Some("aarch64_target_feature")),
122     ("fp16", Some("aarch64_target_feature")),
123     ("rcpc", Some("aarch64_target_feature")),
124     ("dotprod", Some("aarch64_target_feature")),
125     ("v8.1a", Some("aarch64_target_feature")),
126     ("v8.2a", Some("aarch64_target_feature")),
127     ("v8.3a", Some("aarch64_target_feature")),
128 ];
129
130 const X86_WHITELIST: &[(&str, Option<&str>)] = &[
131     ("adx", Some("adx_target_feature")),
132     ("aes", None),
133     ("avx", None),
134     ("avx2", None),
135     ("avx512bw", Some("avx512_target_feature")),
136     ("avx512cd", Some("avx512_target_feature")),
137     ("avx512dq", Some("avx512_target_feature")),
138     ("avx512er", Some("avx512_target_feature")),
139     ("avx512f", Some("avx512_target_feature")),
140     ("avx512ifma", Some("avx512_target_feature")),
141     ("avx512pf", Some("avx512_target_feature")),
142     ("avx512vbmi", Some("avx512_target_feature")),
143     ("avx512vl", Some("avx512_target_feature")),
144     ("avx512vpopcntdq", Some("avx512_target_feature")),
145     ("bmi1", None),
146     ("bmi2", None),
147     ("cmpxchg16b", Some("cmpxchg16b_target_feature")),
148     ("fma", None),
149     ("fxsr", None),
150     ("lzcnt", None),
151     ("mmx", Some("mmx_target_feature")),
152     ("movbe", Some("movbe_target_feature")),
153     ("pclmulqdq", None),
154     ("popcnt", None),
155     ("rdrand", None),
156     ("rdseed", None),
157     ("sha", None),
158     ("sse", None),
159     ("sse2", None),
160     ("sse3", None),
161     ("sse4.1", None),
162     ("sse4.2", None),
163     ("sse4a", Some("sse4a_target_feature")),
164     ("ssse3", None),
165     ("tbm", Some("tbm_target_feature")),
166     ("xsave", None),
167     ("xsavec", None),
168     ("xsaveopt", None),
169     ("xsaves", None),
170 ];
171
172 const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
173     ("hvx", Some("hexagon_target_feature")),
174     ("hvx-double", Some("hexagon_target_feature")),
175 ];
176
177 const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
178     ("altivec", Some("powerpc_target_feature")),
179     ("power8-altivec", Some("powerpc_target_feature")),
180     ("power9-altivec", Some("powerpc_target_feature")),
181     ("power8-vector", Some("powerpc_target_feature")),
182     ("power9-vector", Some("powerpc_target_feature")),
183     ("vsx", Some("powerpc_target_feature")),
184 ];
185
186 const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
187     ("fp64", Some("mips_target_feature")),
188     ("msa", Some("mips_target_feature")),
189 ];
190
191 const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
192     ("simd128", Some("wasm_target_feature")),
193     ("atomics", Some("wasm_target_feature")),
194 ];
195
196 /// When rustdoc is running, provide a list of all known features so that all their respective
197 /// primitives may be documented.
198 ///
199 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
200 /// iterator!
201 pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
202     ARM_WHITELIST.iter().cloned()
203         .chain(AARCH64_WHITELIST.iter().cloned())
204         .chain(X86_WHITELIST.iter().cloned())
205         .chain(HEXAGON_WHITELIST.iter().cloned())
206         .chain(POWERPC_WHITELIST.iter().cloned())
207         .chain(MIPS_WHITELIST.iter().cloned())
208         .chain(WASM_WHITELIST.iter().cloned())
209 }
210
211 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
212     let arch = if sess.target.target.arch == "x86_64" {
213         "x86"
214     } else {
215         &*sess.target.target.arch
216     };
217     match (arch, s) {
218         ("x86", "pclmulqdq") => "pclmul",
219         ("x86", "rdrand") => "rdrnd",
220         ("x86", "bmi1") => "bmi",
221         ("x86", "cmpxchg16b") => "cx16",
222         ("aarch64", "fp") => "fp-armv8",
223         ("aarch64", "fp16") => "fullfp16",
224         (_, s) => s,
225     }
226 }
227
228 pub fn target_features(sess: &Session) -> Vec<Symbol> {
229     let target_machine = create_informational_target_machine(sess, true);
230     target_feature_whitelist(sess)
231         .iter()
232         .filter_map(|&(feature, gate)| {
233             if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
234                 Some(feature)
235             } else {
236                 None
237             }
238         })
239         .filter(|feature| {
240             let llvm_feature = to_llvm_feature(sess, feature);
241             let cstr = CString::new(llvm_feature).unwrap();
242             unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
243         })
244         .map(|feature| Symbol::intern(feature)).collect()
245 }
246
247 pub fn target_feature_whitelist(sess: &Session)
248     -> &'static [(&'static str, Option<&'static str>)]
249 {
250     match &*sess.target.target.arch {
251         "arm" => ARM_WHITELIST,
252         "aarch64" => AARCH64_WHITELIST,
253         "x86" | "x86_64" => X86_WHITELIST,
254         "hexagon" => HEXAGON_WHITELIST,
255         "mips" | "mips64" => MIPS_WHITELIST,
256         "powerpc" | "powerpc64" => POWERPC_WHITELIST,
257         // wasm32 on emscripten does not support these target features
258         "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
259         _ => &[],
260     }
261 }
262
263 pub fn print_version() {
264     // Can be called without initializing LLVM
265     unsafe {
266         println!("LLVM version: {}.{}",
267                  llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
268     }
269 }
270
271 pub fn get_major_version() -> u32 {
272     unsafe { llvm::LLVMRustVersionMajor() }
273 }
274
275 pub fn print_passes() {
276     // Can be called without initializing LLVM
277     unsafe { llvm::LLVMRustPrintPasses(); }
278 }
279
280 pub(crate) fn print(req: PrintRequest, sess: &Session) {
281     require_inited();
282     let tm = create_informational_target_machine(sess, true);
283     unsafe {
284         match req {
285             PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
286             PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
287             _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
288         }
289     }
290 }
291
292 pub fn target_cpu(sess: &Session) -> &str {
293     let name = match sess.opts.cg.target_cpu {
294         Some(ref s) => &**s,
295         None => &*sess.target.target.options.cpu
296     };
297     if name != "native" {
298         return name
299     }
300
301     unsafe {
302         let mut len = 0;
303         let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
304         str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
305     }
306 }