rust/src/librustc_trans/llvm_util.rs

191 lines
6.9 KiB
Rust
Raw Normal View History

// 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;
use libc::c_int;
2018-02-11 00:27:04 +00:00
use std::ffi::CString;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();
pub(crate) fn init(sess: &Session) {
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.
POISONED.store(true, Ordering::SeqCst);
}
configure_llvm(sess);
});
if POISONED.load(Ordering::SeqCst) {
bug!("couldn't enable multi-threaded LLVM");
}
}
}
fn require_inited() {
INIT.call_once(|| bug!("llvm is not initialized"));
if POISONED.load(Ordering::SeqCst) {
bug!("couldn't enable multi-threaded LLVM");
}
}
unsafe fn configure_llvm(sess: &Session) {
let mut llvm_c_strs = Vec::new();
let mut llvm_args = Vec::new();
{
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"); }
if sess.opts.debugging_opts.disable_instrumentation_preinliner {
add("-disable-preinline");
}
for arg in &sess.opts.cg.llvm_args {
add(&(*arg));
}
}
llvm::LLVMInitializePasses();
llvm::initialize_available_targets();
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
llvm_args.as_ptr());
}
2018-02-21 06:59:28 +00:00
// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
2018-02-27 02:05:58 +00:00
const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto",
"ras", "lse", "rdm", "fp16", "rcpc",
"dotprod", "v8.1a", "v8.2a", "v8.3a"];
2018-02-20 13:08:22 +00:00
const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
"avx512cd", "avx512dq", "avx512er",
"avx512f", "avx512ifma", "avx512pf",
"avx512vbmi", "avx512vl", "avx512vpopcntdq",
"bmi1", "bmi2", "fma", "fxsr",
2018-02-20 13:08:22 +00:00
"lzcnt", "mmx", "pclmulqdq",
"popcnt", "rdrand", "rdseed",
"sha",
2018-02-20 13:08:22 +00:00
"sse", "sse2", "sse3", "sse4.1",
"sse4.2", "sse4a", "ssse3",
"tbm", "xsave", "xsavec",
"xsaveopt", "xsaves"];
const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
"power8-altivec", "power9-altivec",
"power8-vector", "power9-vector",
"vsx"];
const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"];
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primtives may be documented.
///
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
/// iterator!
pub fn all_known_features() -> impl Iterator<Item=&'static str> {
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-02-27 02:05:58 +00: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 21:34:15 +00:00
("aarch64", "fp") => "fp-armv8",
2018-02-27 02:05:58 +00:00
("aarch64", "fp16") => "fullfp16",
(_, s) => s,
}
}
2017-11-28 09:28:15 +00:00
pub fn target_features(sess: &Session) -> Vec<Symbol> {
2018-04-01 06:26:05 +00:00
let target_machine = create_target_machine(sess, true);
2018-02-10 23:36:22 +00:00
target_feature_whitelist(sess)
.iter()
.filter(|feature| {
2018-02-27 02:05:58 +00:00
let llvm_feature = to_llvm_feature(sess, feature);
2018-02-11 12:57:07 +00:00
let cstr = CString::new(llvm_feature).unwrap();
unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
2018-02-10 23:36:22 +00:00
})
2018-02-11 00:27:04 +00:00
.map(|feature| Symbol::intern(feature)).collect()
}
pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
2018-02-11 00:27:04 +00:00
match &*sess.target.target.arch {
2017-10-16 11:33:43 +00:00
"arm" => ARM_WHITELIST,
"aarch64" => AARCH64_WHITELIST,
"x86" | "x86_64" => X86_WHITELIST,
"hexagon" => HEXAGON_WHITELIST,
2017-11-28 09:28:15 +00:00
"mips" | "mips64" => MIPS_WHITELIST,
"powerpc" | "powerpc64" => POWERPC_WHITELIST,
_ => &[],
}
}
pub fn print_version() {
// Can be called without initializing LLVM
unsafe {
println!("LLVM version: {}.{}",
llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
}
}
pub fn print_passes() {
// Can be called without initializing LLVM
unsafe { llvm::LLVMRustPrintPasses(); }
}
pub(crate) fn print(req: PrintRequest, sess: &Session) {
require_inited();
2018-04-01 06:26:05 +00:00
let tm = create_target_machine(sess, true);
unsafe {
match req {
PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
_ => bug!("rustc_trans can't handle print request: {:?}", req),
}
}
}