Skip to content

Commit 92e3fb3

Browse files
committed
Auto merge of #31709 - ranma42:target_feature-from-llvm, r=alexcrichton
Compute `target_feature` from LLVM This is a work-in-progress fix for #31662. The logic that computes the target features from the command line has been replaced with queries to the `TargetMachine`.
2 parents 6ece144 + ce99a5e commit 92e3fb3

File tree

13 files changed

+203
-117
lines changed

13 files changed

+203
-117
lines changed

mk/crates.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \
9797
rustc_back graphviz
9898

9999
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
100-
log graphviz rustc_back rustc_data_structures\
100+
log graphviz rustc_llvm rustc_back rustc_data_structures\
101101
rustc_const_math
102102
DEPS_rustc_back := std syntax flate log libc
103103
DEPS_rustc_borrowck := rustc rustc_mir log graphviz syntax

mk/rustllvm.mk

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ $$(RT_OUTPUT_DIR_$(1))/$$(call CFG_STATIC_LIB_NAME_$(1),rustllvm): \
4343
@$$(call E, link: $$@)
4444
$$(Q)$$(call CFG_CREATE_ARCHIVE_$(1),$$@) $$^
4545

46+
RUSTLLVM_COMPONENTS_$(1) = $$(shell echo $$(LLVM_ALL_COMPONENTS_$(1)) |\
47+
tr 'a-z-' 'A-Z_'| sed -e 's/^ //;s/\([^ ]*\)/\-DLLVM_COMPONENT_\1/g')
48+
4649
# On MSVC we need to double-escape arguments that llvm-config printed which
4750
# start with a '/'. The shell we're running in will auto-translate the argument
4851
# `/foo` to `C:/msys64/foo` but we really want it to be passed through as `/foo`
@@ -51,6 +54,7 @@ $(1)/rustllvm/%.o: $(S)src/rustllvm/%.cpp $$(MKFILE_DEPS) $$(LLVM_CONFIG_$(1))
5154
@$$(call E, compile: $$@)
5255
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@,) \
5356
$$(subst /,//,$$(LLVM_CXXFLAGS_$(1))) \
57+
$$(RUSTLLVM_COMPONENTS_$(1)) \
5458
$$(EXTRA_RUSTLLVM_CXXFLAGS_$(1)) \
5559
$$(RUSTLLVM_INCS_$(1)) \
5660
$$<

src/librustc/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ rustc_back = { path = "../librustc_back" }
1919
rustc_bitflags = { path = "../librustc_bitflags" }
2020
rustc_const_math = { path = "../librustc_const_math" }
2121
rustc_data_structures = { path = "../librustc_data_structures" }
22+
rustc_llvm = { path = "../librustc_llvm" }
2223
serialize = { path = "../libserialize" }
2324
syntax = { path = "../libsyntax" }

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ extern crate getopts;
4949
extern crate graphviz;
5050
extern crate libc;
5151
extern crate rbml;
52+
extern crate rustc_llvm as llvm;
5253
extern crate rustc_back;
5354
extern crate rustc_data_structures;
5455
extern crate serialize;

src/librustc/session/mod.rs

+57
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@ use syntax::{ast, codemap};
3030
use syntax::feature_gate::AttributeType;
3131

3232
use rustc_back::target::Target;
33+
use llvm;
3334

3435
use std::path::{Path, PathBuf};
3536
use std::cell::{Cell, RefCell};
3637
use std::collections::{HashMap, HashSet};
3738
use std::env;
39+
use std::ffi::CString;
3840
use std::rc::Rc;
3941
use std::fmt;
42+
use libc::c_int;
4043

4144
pub mod config;
4245
pub mod filesearch;
@@ -491,9 +494,63 @@ pub fn build_session_(sopts: config::Options,
491494
imported_macro_spans: RefCell::new(HashMap::new()),
492495
};
493496

497+
init_llvm(&sess);
498+
494499
sess
495500
}
496501

502+
fn init_llvm(sess: &Session) {
503+
unsafe {
504+
// Before we touch LLVM, make sure that multithreading is enabled.
505+
use std::sync::Once;
506+
static INIT: Once = Once::new();
507+
static mut POISONED: bool = false;
508+
INIT.call_once(|| {
509+
if llvm::LLVMStartMultithreaded() != 1 {
510+
// use an extra bool to make sure that all future usage of LLVM
511+
// cannot proceed despite the Once not running more than once.
512+
POISONED = true;
513+
}
514+
515+
configure_llvm(sess);
516+
});
517+
518+
if POISONED {
519+
bug!("couldn't enable multi-threaded LLVM");
520+
}
521+
}
522+
}
523+
524+
unsafe fn configure_llvm(sess: &Session) {
525+
let mut llvm_c_strs = Vec::new();
526+
let mut llvm_args = Vec::new();
527+
528+
{
529+
let mut add = |arg: &str| {
530+
let s = CString::new(arg).unwrap();
531+
llvm_args.push(s.as_ptr());
532+
llvm_c_strs.push(s);
533+
};
534+
add("rustc"); // fake program name
535+
if sess.time_llvm_passes() { add("-time-passes"); }
536+
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
537+
538+
// FIXME #21627 disable faulty FastISel on AArch64 (even for -O0)
539+
if sess.target.target.arch == "aarch64" { add("-fast-isel=0"); }
540+
541+
for arg in &sess.opts.cg.llvm_args {
542+
add(&(*arg));
543+
}
544+
}
545+
546+
llvm::LLVMInitializePasses();
547+
548+
llvm::initialize_available_targets();
549+
550+
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
551+
llvm_args.as_ptr());
552+
}
553+
497554
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
498555
let mut emitter: Box<Emitter> = match output {
499556
config::ErrorOutputType::HumanReadable(color_config) => {

src/librustc_driver/target_features.rs

+40-65
Original file line numberDiff line numberDiff line change
@@ -9,79 +9,54 @@
99
// except according to those terms.
1010

1111
use syntax::{ast, attr};
12+
use llvm::LLVMRustHasFeature;
1213
use rustc::session::Session;
14+
use rustc_trans::back::write::create_target_machine;
1315
use syntax::parse::token::InternedString;
1416
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+
];
1540

1641
/// Add `target_feature = "..."` cfgs for a variety of platform
1742
/// specific features (SSE, NEON etc.).
1843
///
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.
2646
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);
4948

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+
};
5354

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+
}
8762
}

src/librustc_llvm/build.rs

+7
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ fn main() {
100100
}
101101
cfg.flag(flag);
102102
}
103+
104+
for component in &components[..] {
105+
let mut flag = String::from("-DLLVM_COMPONENT_");
106+
flag.push_str(&component.to_uppercase());
107+
cfg.flag(&flag);
108+
}
109+
103110
cfg.file("../rustllvm/ExecutionEngineWrapper.cpp")
104111
.file("../rustllvm/PassWrapper.cpp")
105112
.file("../rustllvm/RustWrapper.cpp")

src/librustc_llvm/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2013,6 +2013,9 @@ extern {
20132013
pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef;
20142014
pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef);
20152015

2016+
pub fn LLVMRustHasFeature(T: TargetMachineRef,
2017+
s: *const c_char) -> bool;
2018+
20162019
pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
20172020
CPU: *const c_char,
20182021
Features: *const c_char,

src/librustc_trans/back/write.rs

+1-31
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use std::str;
3131
use std::sync::{Arc, Mutex};
3232
use std::sync::mpsc::channel;
3333
use std::thread;
34-
use libc::{c_uint, c_int, c_void};
34+
use libc::{c_uint, c_void};
3535

3636
pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! {
3737
match llvm::last_error() {
@@ -984,36 +984,6 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
984984
}
985985
}
986986

987-
pub unsafe fn configure_llvm(sess: &Session) {
988-
let mut llvm_c_strs = Vec::new();
989-
let mut llvm_args = Vec::new();
990-
991-
{
992-
let mut add = |arg: &str| {
993-
let s = CString::new(arg).unwrap();
994-
llvm_args.push(s.as_ptr());
995-
llvm_c_strs.push(s);
996-
};
997-
add("rustc"); // fake program name
998-
if sess.time_llvm_passes() { add("-time-passes"); }
999-
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
1000-
1001-
// FIXME #21627 disable faulty FastISel on AArch64 (even for -O0)
1002-
if sess.target.target.arch == "aarch64" { add("-fast-isel=0"); }
1003-
1004-
for arg in &sess.opts.cg.llvm_args {
1005-
add(&(*arg));
1006-
}
1007-
}
1008-
1009-
llvm::LLVMInitializePasses();
1010-
1011-
llvm::initialize_available_targets();
1012-
1013-
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
1014-
llvm_args.as_ptr());
1015-
}
1016-
1017987
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
1018988
config: &ModuleConfig,
1019989
f: &mut FnMut(llvm::PassManagerBuilderRef)) {

src/librustc_trans/base.rs

-20
Original file line numberDiff line numberDiff line change
@@ -2713,26 +2713,6 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
27132713
tcx.sess.opts.debug_assertions
27142714
};
27152715

2716-
// Before we touch LLVM, make sure that multithreading is enabled.
2717-
unsafe {
2718-
use std::sync::Once;
2719-
static INIT: Once = Once::new();
2720-
static mut POISONED: bool = false;
2721-
INIT.call_once(|| {
2722-
if llvm::LLVMStartMultithreaded() != 1 {
2723-
// use an extra bool to make sure that all future usage of LLVM
2724-
// cannot proceed despite the Once not running more than once.
2725-
POISONED = true;
2726-
}
2727-
2728-
::back::write::configure_llvm(&tcx.sess);
2729-
});
2730-
2731-
if POISONED {
2732-
bug!("couldn't enable multi-threaded LLVM");
2733-
}
2734-
}
2735-
27362716
let link_meta = link::build_link_meta(&tcx, name);
27372717

27382718
let codegen_units = tcx.sess.opts.cg.codegen_units;

0 commit comments

Comments
 (0)