Skip to content

Commit

Permalink
Expose the features computed from LLVM in cfg!
Browse files Browse the repository at this point in the history
Instead of relying on the features explicitly passed through the
command line, compute them from the LLVM `TargetMachine`.
  • Loading branch information
ranma42 committed Apr 8, 2016
1 parent c883463 commit 92e24b9
Showing 1 changed file with 31 additions and 63 deletions.
94 changes: 31 additions & 63 deletions src/librustc_driver/target_features.rs
Expand Up @@ -9,79 +9,47 @@
// except according to those terms.

use syntax::{ast, attr};
use llvm::LLVMRustHasFeature;
use rustc::session::Session;
use rustc_trans::back::write::create_target_machine;
use syntax::parse::token::InternedString;
use syntax::parse::token::intern_and_get_ident as intern;
use libc::c_char;

/// Add `target_feature = "..."` cfgs for a variety of platform
/// specific features (SSE, NEON etc.).
///
/// This uses a scheme similar to that employed by clang: reimplement
/// the target feature knowledge. *Theoretically* we could query LLVM
/// since that has perfect knowledge about what things are enabled in
/// code-generation, however, it is extremely non-obvious how to do
/// this successfully. Each platform defines a subclass of a
/// SubtargetInfo, which knows all this information, but the ways to
/// query them do not seem to be public.
/// This is performed by checking whether a whitelisted set of
/// features is available on the target machine, by querying LLVM.
pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
let tf = InternedString::new("target_feature");
macro_rules! fillout {
($($func: ident, $name: expr;)*) => {{
$(if $func(sess) {
cfg.push(attr::mk_name_value_item_str(tf.clone(), intern($name)))
})*
}}
}
fillout! {
has_sse, "sse";
has_sse2, "sse2";
has_sse3, "sse3";
has_ssse3, "ssse3";
has_sse41, "sse4.1";
has_sse42, "sse4.2";
has_avx, "avx";
has_avx2, "avx2";
has_neon, "neon";
has_vfp, "vfp";
}
}
let target_machine = create_target_machine(sess);

let arm_whitelist = [
"neon\0",
"vfp\0",
];

fn features_contain(sess: &Session, s: &str) -> bool {
sess.target.target.options.features.contains(s) || sess.opts.cg.target_feature.contains(s)
}
let x86_whitelist = [
"avx\0",
"avx2\0",
"sse\0",
"sse2\0",
"sse3\0",
"sse4.1\0",
"sse4.2\0",
"ssse3\0",
];

pub fn has_sse(sess: &Session) -> bool {
features_contain(sess, "+sse") || has_sse2(sess)
}
pub fn has_sse2(sess: &Session) -> bool {
// x86-64 requires at least SSE2 support
sess.target.target.arch == "x86_64" || features_contain(sess, "+sse2") || has_sse3(sess)
}
pub fn has_sse3(sess: &Session) -> bool {
features_contain(sess, "+sse3") || has_ssse3(sess)
}
pub fn has_ssse3(sess: &Session) -> bool {
features_contain(sess, "+ssse3") || has_sse41(sess)
}
pub fn has_sse41(sess: &Session) -> bool {
features_contain(sess, "+sse4.1") || has_sse42(sess)
}
pub fn has_sse42(sess: &Session) -> bool {
features_contain(sess, "+sse4.2") || has_avx(sess)
}
pub fn has_avx(sess: &Session) -> bool {
features_contain(sess, "+avx") || has_avx2(sess)
}
pub fn has_avx2(sess: &Session) -> bool {
features_contain(sess, "+avx2")
}
let whitelist = match &*sess.target.target.arch {
"arm" => &arm_whitelist[..],
"x86" | "x86_64" => &x86_whitelist[..],
_ => &[][..],
};

pub fn has_neon(sess: &Session) -> bool {
// AArch64 requires NEON support
sess.target.target.arch == "aarch64" || features_contain(sess, "+neon")
}
pub fn has_vfp(sess: &Session) -> bool {
// AArch64 requires VFP support
sess.target.target.arch == "aarch64" || features_contain(sess, "+vfp")
let tf = InternedString::new("target_feature");
for feat in whitelist {
if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(feat)))
}
}
}

0 comments on commit 92e24b9

Please sign in to comment.