1 use crate::back::write::create_informational_target_machine;
3 use syntax_pos::symbol::Symbol;
4 use rustc::session::Session;
5 use rustc::session::config::PrintRequest;
6 use rustc_target::spec::MergeFunctions;
9 use syntax::feature_gate::UnstableFeatures;
13 use std::sync::atomic::{AtomicBool, Ordering};
16 static POISONED: AtomicBool = AtomicBool::new(false);
17 static INIT: Once = Once::new();
19 pub(crate) fn init(sess: &Session) {
21 // Before we touch LLVM, make sure that multithreading is enabled.
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);
32 if POISONED.load(Ordering::SeqCst) {
33 bug!("couldn't enable multi-threaded LLVM");
39 INIT.call_once(|| bug!("llvm is not initialized"));
40 if POISONED.load(Ordering::SeqCst) {
41 bug!("couldn't enable multi-threaded LLVM");
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);
50 llvm::LLVMRustInstallFatalErrorHandler();
53 let mut add = |arg: &str| {
54 let s = CString::new(arg).unwrap();
55 llvm_args.push(s.as_ptr());
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");
64 if get_major_version() >= 8 {
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");
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");
79 for arg in &sess.opts.cg.llvm_args {
84 llvm::LLVMInitializePasses();
86 ::rustc_llvm::initialize_available_targets();
88 llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
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.
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")),
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")),
130 const X86_WHITELIST: &[(&str, Option<&str>)] = &[
131 ("adx", Some("adx_target_feature")),
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")),
147 ("cmpxchg16b", Some("cmpxchg16b_target_feature")),
148 ("f16c", Some("f16c_target_feature")),
152 ("mmx", Some("mmx_target_feature")),
153 ("movbe", Some("movbe_target_feature")),
158 ("rtm", Some("rtm_target_feature")),
165 ("sse4a", Some("sse4a_target_feature")),
167 ("tbm", Some("tbm_target_feature")),
174 const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
175 ("hvx", Some("hexagon_target_feature")),
176 ("hvx-double", Some("hexagon_target_feature")),
179 const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
180 ("altivec", Some("powerpc_target_feature")),
181 ("power8-altivec", Some("powerpc_target_feature")),
182 ("power9-altivec", Some("powerpc_target_feature")),
183 ("power8-vector", Some("powerpc_target_feature")),
184 ("power9-vector", Some("powerpc_target_feature")),
185 ("vsx", Some("powerpc_target_feature")),
188 const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
189 ("fp64", Some("mips_target_feature")),
190 ("msa", Some("mips_target_feature")),
193 const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
194 ("simd128", Some("wasm_target_feature")),
195 ("atomics", Some("wasm_target_feature")),
198 /// When rustdoc is running, provide a list of all known features so that all their respective
199 /// primitives may be documented.
201 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
203 pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
204 ARM_WHITELIST.iter().cloned()
205 .chain(AARCH64_WHITELIST.iter().cloned())
206 .chain(X86_WHITELIST.iter().cloned())
207 .chain(HEXAGON_WHITELIST.iter().cloned())
208 .chain(POWERPC_WHITELIST.iter().cloned())
209 .chain(MIPS_WHITELIST.iter().cloned())
210 .chain(WASM_WHITELIST.iter().cloned())
213 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
214 let arch = if sess.target.target.arch == "x86_64" {
217 &*sess.target.target.arch
220 ("x86", "pclmulqdq") => "pclmul",
221 ("x86", "rdrand") => "rdrnd",
222 ("x86", "bmi1") => "bmi",
223 ("x86", "cmpxchg16b") => "cx16",
224 ("aarch64", "fp") => "fp-armv8",
225 ("aarch64", "fp16") => "fullfp16",
230 pub fn target_features(sess: &Session) -> Vec<Symbol> {
231 let target_machine = create_informational_target_machine(sess, true);
232 target_feature_whitelist(sess)
234 .filter_map(|&(feature, gate)| {
235 if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
242 let llvm_feature = to_llvm_feature(sess, feature);
243 let cstr = CString::new(llvm_feature).unwrap();
244 unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
246 .map(|feature| Symbol::intern(feature)).collect()
249 pub fn target_feature_whitelist(sess: &Session)
250 -> &'static [(&'static str, Option<&'static str>)]
252 match &*sess.target.target.arch {
253 "arm" => ARM_WHITELIST,
254 "aarch64" => AARCH64_WHITELIST,
255 "x86" | "x86_64" => X86_WHITELIST,
256 "hexagon" => HEXAGON_WHITELIST,
257 "mips" | "mips64" => MIPS_WHITELIST,
258 "powerpc" | "powerpc64" => POWERPC_WHITELIST,
259 // wasm32 on emscripten does not support these target features
260 "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
265 pub fn print_version() {
266 // Can be called without initializing LLVM
268 println!("LLVM version: {}.{}",
269 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
273 pub fn get_major_version() -> u32 {
274 unsafe { llvm::LLVMRustVersionMajor() }
277 pub fn print_passes() {
278 // Can be called without initializing LLVM
279 unsafe { llvm::LLVMRustPrintPasses(); }
282 pub(crate) fn print(req: PrintRequest, sess: &Session) {
284 let tm = create_informational_target_machine(sess, true);
287 PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
288 PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
289 _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
294 pub fn target_cpu(sess: &Session) -> &str {
295 let name = match sess.opts.cg.target_cpu {
297 None => &*sess.target.target.options.cpu
299 if name != "native" {
305 let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
306 str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()