2017-04-30 13:33:25 -05:00
|
|
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
use syntax_pos::symbol::Symbol;
|
|
|
|
use back::write::create_target_machine;
|
|
|
|
use llvm;
|
|
|
|
use rustc::session::Session;
|
|
|
|
use rustc::session::config::PrintRequest;
|
2018-01-05 15:26:26 -06:00
|
|
|
use libc::c_int;
|
2018-02-10 18:27:04 -06:00
|
|
|
use std::ffi::CString;
|
2018-04-05 10:02:11 -05:00
|
|
|
use syntax::feature_gate::UnstableFeatures;
|
2017-04-30 13:33:25 -05:00
|
|
|
|
2018-08-23 13:03:22 -05:00
|
|
|
use std::str;
|
|
|
|
use std::slice;
|
2017-05-14 13:33:37 -05:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
use std::sync::Once;
|
|
|
|
|
2017-10-30 12:42:21 -05:00
|
|
|
static POISONED: AtomicBool = AtomicBool::new(false);
|
|
|
|
static INIT: Once = Once::new();
|
|
|
|
|
|
|
|
pub(crate) fn init(sess: &Session) {
|
2017-04-30 13:33:25 -05:00
|
|
|
unsafe {
|
|
|
|
// Before we touch LLVM, make sure that multithreading is enabled.
|
|
|
|
INIT.call_once(|| {
|
|
|
|
if llvm::LLVMStartMultithreaded() != 1 {
|
|
|
|
// use an extra bool to make sure that all future usage of LLVM
|
|
|
|
// cannot proceed despite the Once not running more than once.
|
2017-05-14 13:33:37 -05:00
|
|
|
POISONED.store(true, Ordering::SeqCst);
|
2017-04-30 13:33:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
configure_llvm(sess);
|
|
|
|
});
|
|
|
|
|
2017-05-14 13:33:37 -05:00
|
|
|
if POISONED.load(Ordering::SeqCst) {
|
2017-04-30 13:33:25 -05:00
|
|
|
bug!("couldn't enable multi-threaded LLVM");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 12:42:21 -05:00
|
|
|
fn require_inited() {
|
|
|
|
INIT.call_once(|| bug!("llvm is not initialized"));
|
|
|
|
if POISONED.load(Ordering::SeqCst) {
|
|
|
|
bug!("couldn't enable multi-threaded LLVM");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-30 13:33:25 -05:00
|
|
|
unsafe fn configure_llvm(sess: &Session) {
|
2018-10-08 09:55:04 -05:00
|
|
|
let n_args = sess.opts.cg.llvm_args.len();
|
|
|
|
let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
|
|
|
|
let mut llvm_args = Vec::with_capacity(n_args + 1);
|
2017-04-30 13:33:25 -05:00
|
|
|
|
2018-10-12 14:35:55 -05:00
|
|
|
llvm::LLVMRustInstallFatalErrorHandler();
|
|
|
|
|
2017-04-30 13:33:25 -05:00
|
|
|
{
|
|
|
|
let mut add = |arg: &str| {
|
|
|
|
let s = CString::new(arg).unwrap();
|
|
|
|
llvm_args.push(s.as_ptr());
|
|
|
|
llvm_c_strs.push(s);
|
|
|
|
};
|
|
|
|
add("rustc"); // fake program name
|
|
|
|
if sess.time_llvm_passes() { add("-time-passes"); }
|
|
|
|
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
|
2018-03-12 15:15:16 -05:00
|
|
|
if sess.opts.debugging_opts.disable_instrumentation_preinliner {
|
|
|
|
add("-disable-preinline");
|
|
|
|
}
|
2018-11-29 16:05:23 -06:00
|
|
|
if llvm::LLVMRustIsRustLLVM() {
|
|
|
|
add("-mergefunc-use-aliases");
|
|
|
|
}
|
2017-04-30 13:33:25 -05:00
|
|
|
|
|
|
|
for arg in &sess.opts.cg.llvm_args {
|
|
|
|
add(&(*arg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::LLVMInitializePasses();
|
|
|
|
|
2018-05-29 12:41:36 -05:00
|
|
|
::rustc_llvm::initialize_available_targets();
|
2017-04-30 13:33:25 -05:00
|
|
|
|
|
|
|
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
|
|
|
|
llvm_args.as_ptr());
|
|
|
|
}
|
|
|
|
|
2018-02-21 00:59:28 -06:00
|
|
|
// WARNING: the features after applying `to_llvm_feature` must be known
|
2018-02-20 07:05:25 -06:00
|
|
|
// to LLVM or the feature detection code will walk past the end of the feature
|
|
|
|
// array, leading to crashes.
|
2017-04-30 13:33:25 -05:00
|
|
|
|
2018-04-05 10:02:11 -05:00
|
|
|
const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
|
2018-09-03 09:52:43 -05:00
|
|
|
("aclass", Some("arm_target_feature")),
|
2018-07-06 17:12:03 -05:00
|
|
|
("mclass", Some("arm_target_feature")),
|
2018-07-25 02:27:55 -05:00
|
|
|
("rclass", Some("arm_target_feature")),
|
|
|
|
("dsp", Some("arm_target_feature")),
|
2018-04-05 10:02:11 -05:00
|
|
|
("neon", Some("arm_target_feature")),
|
2018-09-03 09:52:43 -05:00
|
|
|
("v5te", Some("arm_target_feature")),
|
|
|
|
("v6k", Some("arm_target_feature")),
|
|
|
|
("v6t2", Some("arm_target_feature")),
|
2018-04-05 10:02:11 -05:00
|
|
|
("v7", Some("arm_target_feature")),
|
|
|
|
("vfp2", Some("arm_target_feature")),
|
|
|
|
("vfp3", Some("arm_target_feature")),
|
|
|
|
("vfp4", Some("arm_target_feature")),
|
|
|
|
];
|
|
|
|
|
|
|
|
const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
|
|
|
|
("fp", Some("aarch64_target_feature")),
|
|
|
|
("neon", Some("aarch64_target_feature")),
|
|
|
|
("sve", Some("aarch64_target_feature")),
|
|
|
|
("crc", Some("aarch64_target_feature")),
|
|
|
|
("crypto", Some("aarch64_target_feature")),
|
|
|
|
("ras", Some("aarch64_target_feature")),
|
|
|
|
("lse", Some("aarch64_target_feature")),
|
|
|
|
("rdm", Some("aarch64_target_feature")),
|
|
|
|
("fp16", Some("aarch64_target_feature")),
|
|
|
|
("rcpc", Some("aarch64_target_feature")),
|
|
|
|
("dotprod", Some("aarch64_target_feature")),
|
|
|
|
("v8.1a", Some("aarch64_target_feature")),
|
|
|
|
("v8.2a", Some("aarch64_target_feature")),
|
|
|
|
("v8.3a", Some("aarch64_target_feature")),
|
|
|
|
];
|
|
|
|
|
|
|
|
const X86_WHITELIST: &[(&str, Option<&str>)] = &[
|
2018-12-12 10:37:56 -06:00
|
|
|
("adx", Some("adx_target_feature")),
|
2018-04-05 10:02:11 -05:00
|
|
|
("aes", None),
|
|
|
|
("avx", None),
|
|
|
|
("avx2", None),
|
|
|
|
("avx512bw", Some("avx512_target_feature")),
|
|
|
|
("avx512cd", Some("avx512_target_feature")),
|
|
|
|
("avx512dq", Some("avx512_target_feature")),
|
|
|
|
("avx512er", Some("avx512_target_feature")),
|
|
|
|
("avx512f", Some("avx512_target_feature")),
|
|
|
|
("avx512ifma", Some("avx512_target_feature")),
|
|
|
|
("avx512pf", Some("avx512_target_feature")),
|
|
|
|
("avx512vbmi", Some("avx512_target_feature")),
|
|
|
|
("avx512vl", Some("avx512_target_feature")),
|
|
|
|
("avx512vpopcntdq", Some("avx512_target_feature")),
|
|
|
|
("bmi1", None),
|
|
|
|
("bmi2", None),
|
|
|
|
("fma", None),
|
|
|
|
("fxsr", None),
|
|
|
|
("lzcnt", None),
|
|
|
|
("mmx", Some("mmx_target_feature")),
|
|
|
|
("pclmulqdq", None),
|
|
|
|
("popcnt", None),
|
|
|
|
("rdrand", None),
|
|
|
|
("rdseed", None),
|
|
|
|
("sha", None),
|
|
|
|
("sse", None),
|
|
|
|
("sse2", None),
|
|
|
|
("sse3", None),
|
|
|
|
("sse4.1", None),
|
|
|
|
("sse4.2", None),
|
|
|
|
("sse4a", Some("sse4a_target_feature")),
|
|
|
|
("ssse3", None),
|
|
|
|
("tbm", Some("tbm_target_feature")),
|
|
|
|
("xsave", None),
|
|
|
|
("xsavec", None),
|
|
|
|
("xsaveopt", None),
|
|
|
|
("xsaves", None),
|
|
|
|
];
|
|
|
|
|
|
|
|
const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
|
|
|
|
("hvx", Some("hexagon_target_feature")),
|
|
|
|
("hvx-double", Some("hexagon_target_feature")),
|
|
|
|
];
|
|
|
|
|
|
|
|
const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
|
|
|
|
("altivec", Some("powerpc_target_feature")),
|
|
|
|
("power8-altivec", Some("powerpc_target_feature")),
|
|
|
|
("power9-altivec", Some("powerpc_target_feature")),
|
|
|
|
("power8-vector", Some("powerpc_target_feature")),
|
|
|
|
("power9-vector", Some("powerpc_target_feature")),
|
|
|
|
("vsx", Some("powerpc_target_feature")),
|
|
|
|
];
|
|
|
|
|
|
|
|
const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
|
|
|
|
("fp64", Some("mips_target_feature")),
|
|
|
|
("msa", Some("mips_target_feature")),
|
|
|
|
];
|
2018-02-10 17:27:21 -06:00
|
|
|
|
2018-08-07 18:39:52 -05:00
|
|
|
const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
|
|
|
|
("simd128", Some("wasm_target_feature")),
|
2018-09-01 00:41:17 -05:00
|
|
|
("atomics", Some("wasm_target_feature")),
|
2018-08-07 18:39:52 -05:00
|
|
|
];
|
|
|
|
|
2018-03-20 19:36:30 -05:00
|
|
|
/// When rustdoc is running, provide a list of all known features so that all their respective
|
2018-11-11 07:52:36 -06:00
|
|
|
/// primitives may be documented.
|
2018-03-20 19:36:30 -05:00
|
|
|
///
|
|
|
|
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
|
|
|
|
/// iterator!
|
2018-04-05 10:02:11 -05:00
|
|
|
pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
|
2018-03-20 19:36:30 -05:00
|
|
|
ARM_WHITELIST.iter().cloned()
|
|
|
|
.chain(AARCH64_WHITELIST.iter().cloned())
|
|
|
|
.chain(X86_WHITELIST.iter().cloned())
|
|
|
|
.chain(HEXAGON_WHITELIST.iter().cloned())
|
|
|
|
.chain(POWERPC_WHITELIST.iter().cloned())
|
|
|
|
.chain(MIPS_WHITELIST.iter().cloned())
|
2018-08-07 18:39:52 -05:00
|
|
|
.chain(WASM_WHITELIST.iter().cloned())
|
2018-03-20 19:36:30 -05:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:05:58 -06:00
|
|
|
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
|
|
|
|
let arch = if sess.target.target.arch == "x86_64" {
|
|
|
|
"x86"
|
|
|
|
} else {
|
|
|
|
&*sess.target.target.arch
|
|
|
|
};
|
|
|
|
match (arch, s) {
|
|
|
|
("x86", "pclmulqdq") => "pclmul",
|
|
|
|
("x86", "rdrand") => "rdrnd",
|
|
|
|
("x86", "bmi1") => "bmi",
|
2018-04-10 16:34:15 -05:00
|
|
|
("aarch64", "fp") => "fp-armv8",
|
2018-02-26 20:05:58 -06:00
|
|
|
("aarch64", "fp16") => "fullfp16",
|
|
|
|
(_, s) => s,
|
2018-02-10 17:27:21 -06:00
|
|
|
}
|
|
|
|
}
|
2017-11-28 03:28:15 -06:00
|
|
|
|
2017-04-30 13:33:25 -05:00
|
|
|
pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
2018-04-01 01:26:05 -05:00
|
|
|
let target_machine = create_target_machine(sess, true);
|
2018-02-10 17:36:22 -06:00
|
|
|
target_feature_whitelist(sess)
|
|
|
|
.iter()
|
2018-04-05 10:02:11 -05:00
|
|
|
.filter_map(|&(feature, gate)| {
|
|
|
|
if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
|
|
|
|
Some(feature)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
2018-02-10 17:36:22 -06:00
|
|
|
.filter(|feature| {
|
2018-02-26 20:05:58 -06:00
|
|
|
let llvm_feature = to_llvm_feature(sess, feature);
|
2018-02-11 06:57:07 -06:00
|
|
|
let cstr = CString::new(llvm_feature).unwrap();
|
|
|
|
unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
|
2018-02-10 17:36:22 -06:00
|
|
|
})
|
2018-02-10 18:27:04 -06:00
|
|
|
.map(|feature| Symbol::intern(feature)).collect()
|
2018-01-05 15:26:26 -06:00
|
|
|
}
|
2017-04-30 13:33:25 -05:00
|
|
|
|
2018-04-05 10:02:11 -05:00
|
|
|
pub fn target_feature_whitelist(sess: &Session)
|
|
|
|
-> &'static [(&'static str, Option<&'static str>)]
|
|
|
|
{
|
2018-02-10 18:27:04 -06:00
|
|
|
match &*sess.target.target.arch {
|
2017-10-16 06:33:43 -05:00
|
|
|
"arm" => ARM_WHITELIST,
|
|
|
|
"aarch64" => AARCH64_WHITELIST,
|
2017-04-30 13:33:25 -05:00
|
|
|
"x86" | "x86_64" => X86_WHITELIST,
|
|
|
|
"hexagon" => HEXAGON_WHITELIST,
|
2017-11-28 03:28:15 -06:00
|
|
|
"mips" | "mips64" => MIPS_WHITELIST,
|
2017-07-22 19:16:43 -05:00
|
|
|
"powerpc" | "powerpc64" => POWERPC_WHITELIST,
|
2018-11-08 09:22:20 -06:00
|
|
|
// wasm32 on emscripten does not support these target features
|
|
|
|
"wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
|
2017-04-30 13:33:25 -05:00
|
|
|
_ => &[],
|
2018-02-10 17:27:21 -06:00
|
|
|
}
|
2017-04-30 13:33:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn print_version() {
|
2017-10-30 12:42:21 -05:00
|
|
|
// Can be called without initializing LLVM
|
2017-04-30 13:33:25 -05:00
|
|
|
unsafe {
|
|
|
|
println!("LLVM version: {}.{}",
|
|
|
|
llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-03 09:48:29 -05:00
|
|
|
pub fn get_major_version() -> u32 {
|
|
|
|
unsafe { llvm::LLVMRustVersionMajor() }
|
|
|
|
}
|
|
|
|
|
2017-04-30 13:33:25 -05:00
|
|
|
pub fn print_passes() {
|
2017-10-30 12:42:21 -05:00
|
|
|
// Can be called without initializing LLVM
|
2017-04-30 13:33:25 -05:00
|
|
|
unsafe { llvm::LLVMRustPrintPasses(); }
|
|
|
|
}
|
|
|
|
|
2017-10-30 12:42:21 -05:00
|
|
|
pub(crate) fn print(req: PrintRequest, sess: &Session) {
|
|
|
|
require_inited();
|
2018-04-01 01:26:05 -05:00
|
|
|
let tm = create_target_machine(sess, true);
|
2017-04-30 13:33:25 -05:00
|
|
|
unsafe {
|
|
|
|
match req {
|
|
|
|
PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
|
|
|
|
PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
|
2018-05-08 08:10:16 -05:00
|
|
|
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
|
2017-04-30 13:33:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-23 13:03:22 -05:00
|
|
|
|
|
|
|
pub fn target_cpu(sess: &Session) -> &str {
|
|
|
|
let name = match sess.opts.cg.target_cpu {
|
|
|
|
Some(ref s) => &**s,
|
|
|
|
None => &*sess.target.target.options.cpu
|
|
|
|
};
|
|
|
|
if name != "native" {
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let mut len = 0;
|
|
|
|
let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
|
|
|
|
str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
|
|
|
|
}
|
|
|
|
}
|