|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | use syntax::{ast, attr};
|
| 12 | +use llvm::LLVMRustHasFeature; |
12 | 13 | use rustc::session::Session;
|
| 14 | +use rustc_trans::back::write::create_target_machine; |
13 | 15 | use syntax::parse::token::InternedString;
|
14 | 16 | use syntax::parse::token::intern_and_get_ident as intern;
|
| 17 | +use libc::c_char; |
| 18 | + |
| 19 | +// WARNING: the features must be known to LLVM or the feature |
| 20 | +// detection code will walk past the end of the feature array, |
| 21 | +// leading to crashes. |
| 22 | + |
| 23 | +const ARM_WHITELIST: &'static [&'static str] = &[ |
| 24 | + "neon\0", |
| 25 | + "vfp2\0", |
| 26 | + "vfp3\0", |
| 27 | + "vfp4\0", |
| 28 | +]; |
| 29 | + |
| 30 | +const X86_WHITELIST: &'static [&'static str] = &[ |
| 31 | + "avx\0", |
| 32 | + "avx2\0", |
| 33 | + "sse\0", |
| 34 | + "sse2\0", |
| 35 | + "sse3\0", |
| 36 | + "sse4.1\0", |
| 37 | + "sse4.2\0", |
| 38 | + "ssse3\0", |
| 39 | +]; |
15 | 40 |
|
16 | 41 | /// Add `target_feature = "..."` cfgs for a variety of platform
|
17 | 42 | /// specific features (SSE, NEON etc.).
|
18 | 43 | ///
|
19 |
| -/// This uses a scheme similar to that employed by clang: reimplement |
20 |
| -/// the target feature knowledge. *Theoretically* we could query LLVM |
21 |
| -/// since that has perfect knowledge about what things are enabled in |
22 |
| -/// code-generation, however, it is extremely non-obvious how to do |
23 |
| -/// this successfully. Each platform defines a subclass of a |
24 |
| -/// SubtargetInfo, which knows all this information, but the ways to |
25 |
| -/// query them do not seem to be public. |
| 44 | +/// This is performed by checking whether a whitelisted set of |
| 45 | +/// features is available on the target machine, by querying LLVM. |
26 | 46 | pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
|
27 |
| - let tf = InternedString::new("target_feature"); |
28 |
| - macro_rules! fillout { |
29 |
| - ($($func: ident, $name: expr;)*) => {{ |
30 |
| - $(if $func(sess) { |
31 |
| - cfg.push(attr::mk_name_value_item_str(tf.clone(), intern($name))) |
32 |
| - })* |
33 |
| - }} |
34 |
| - } |
35 |
| - fillout! { |
36 |
| - has_sse, "sse"; |
37 |
| - has_sse2, "sse2"; |
38 |
| - has_sse3, "sse3"; |
39 |
| - has_ssse3, "ssse3"; |
40 |
| - has_sse41, "sse4.1"; |
41 |
| - has_sse42, "sse4.2"; |
42 |
| - has_avx, "avx"; |
43 |
| - has_avx2, "avx2"; |
44 |
| - has_neon, "neon"; |
45 |
| - has_vfp, "vfp"; |
46 |
| - } |
47 |
| -} |
48 |
| - |
| 47 | + let target_machine = create_target_machine(sess); |
49 | 48 |
|
50 |
| -fn features_contain(sess: &Session, s: &str) -> bool { |
51 |
| - sess.target.target.options.features.contains(s) || sess.opts.cg.target_feature.contains(s) |
52 |
| -} |
| 49 | + let whitelist = match &*sess.target.target.arch { |
| 50 | + "arm" => ARM_WHITELIST, |
| 51 | + "x86" | "x86_64" => X86_WHITELIST, |
| 52 | + _ => &[], |
| 53 | + }; |
53 | 54 |
|
54 |
| -pub fn has_sse(sess: &Session) -> bool { |
55 |
| - features_contain(sess, "+sse") || has_sse2(sess) |
56 |
| -} |
57 |
| -pub fn has_sse2(sess: &Session) -> bool { |
58 |
| - // x86-64 requires at least SSE2 support |
59 |
| - sess.target.target.arch == "x86_64" || features_contain(sess, "+sse2") || has_sse3(sess) |
60 |
| -} |
61 |
| -pub fn has_sse3(sess: &Session) -> bool { |
62 |
| - features_contain(sess, "+sse3") || has_ssse3(sess) |
63 |
| -} |
64 |
| -pub fn has_ssse3(sess: &Session) -> bool { |
65 |
| - features_contain(sess, "+ssse3") || has_sse41(sess) |
66 |
| -} |
67 |
| -pub fn has_sse41(sess: &Session) -> bool { |
68 |
| - features_contain(sess, "+sse4.1") || has_sse42(sess) |
69 |
| -} |
70 |
| -pub fn has_sse42(sess: &Session) -> bool { |
71 |
| - features_contain(sess, "+sse4.2") || has_avx(sess) |
72 |
| -} |
73 |
| -pub fn has_avx(sess: &Session) -> bool { |
74 |
| - features_contain(sess, "+avx") || has_avx2(sess) |
75 |
| -} |
76 |
| -pub fn has_avx2(sess: &Session) -> bool { |
77 |
| - features_contain(sess, "+avx2") |
78 |
| -} |
79 |
| - |
80 |
| -pub fn has_neon(sess: &Session) -> bool { |
81 |
| - // AArch64 requires NEON support |
82 |
| - sess.target.target.arch == "aarch64" || features_contain(sess, "+neon") |
83 |
| -} |
84 |
| -pub fn has_vfp(sess: &Session) -> bool { |
85 |
| - // AArch64 requires VFP support |
86 |
| - sess.target.target.arch == "aarch64" || features_contain(sess, "+vfp") |
| 55 | + let tf = InternedString::new("target_feature"); |
| 56 | + for feat in whitelist { |
| 57 | + assert_eq!(feat.chars().last(), Some('\0')); |
| 58 | + if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } { |
| 59 | + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len()-1]))) |
| 60 | + } |
| 61 | + } |
87 | 62 | }
|
0 commit comments