From 64a35f9d23d983dac2c38c0a97627785f7c5dbfd Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 30 Mar 2016 12:11:58 +0200 Subject: [PATCH 01/10] Reintroduce rustc_llvm dependency in rustc The dependency was removed in 352b44d1fa9ec2c969d7c8360106e6838233bcba, but it is needed in order to compute the target features. --- mk/crates.mk | 2 +- src/librustc/Cargo.toml | 1 + src/librustc/lib.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mk/crates.mk b/mk/crates.mk index dafda75f5fe..fedf6baeee3 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -97,7 +97,7 @@ DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \ rustc_back graphviz DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \ - log graphviz rustc_back rustc_data_structures\ + log graphviz rustc_llvm rustc_back rustc_data_structures\ rustc_const_math DEPS_rustc_back := std syntax flate log libc DEPS_rustc_borrowck := rustc rustc_mir log graphviz syntax diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index d77268219fc..9291227a734 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -19,5 +19,6 @@ rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_llvm = { path = "../librustc_llvm" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index deb20627772..1947cb695e4 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -51,6 +51,7 @@ extern crate getopts; extern crate graphviz; extern crate libc; extern crate rbml; +extern crate rustc_llvm as llvm; extern crate rustc_back; extern crate rustc_data_structures; extern crate serialize; From c883463e9481ca58c9c3b0aefe7873c88e2aa4e0 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Tue, 16 Feb 2016 17:07:30 +0100 Subject: [PATCH 02/10] Implement feature extraction from `TargetMachine` Add the `LLVMRustHasFeature` function to check whether a `TargetMachine` has a given feature. --- mk/rustllvm.mk | 4 +++ src/librustc_llvm/build.rs | 7 ++++ src/librustc_llvm/lib.rs | 3 ++ src/rustllvm/PassWrapper.cpp | 69 ++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk index 6adffda7d1b..834a11d37fa 100644 --- a/mk/rustllvm.mk +++ b/mk/rustllvm.mk @@ -43,6 +43,9 @@ $$(RT_OUTPUT_DIR_$(1))/$$(call CFG_STATIC_LIB_NAME_$(1),rustllvm): \ @$$(call E, link: $$@) $$(Q)$$(call CFG_CREATE_ARCHIVE_$(1),$$@) $$^ +RUSTLLVM_COMPONENTS_$(1) = $$(shell echo $$(LLVM_ALL_COMPONENTS_$(1)) |\ + tr 'a-z-' 'A-Z_'| sed -e 's/^ //;s/\([^ ]*\)/\-DLLVM_COMPONENT_\1/g') + # On MSVC we need to double-escape arguments that llvm-config printed which # start with a '/'. The shell we're running in will auto-translate the argument # `/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)) @$$(call E, compile: $$@) $$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@,) \ $$(subst /,//,$$(LLVM_CXXFLAGS_$(1))) \ + $$(RUSTLLVM_COMPONENTS_$(1)) \ $$(EXTRA_RUSTLLVM_CXXFLAGS_$(1)) \ $$(RUSTLLVM_INCS_$(1)) \ $$< diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index dcfb518ba79..0c6db2cb8ba 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -100,6 +100,13 @@ fn main() { } cfg.flag(flag); } + + for component in &components[..] { + let mut flag = String::from("-DLLVM_COMPONENT_"); + flag.push_str(&component.to_uppercase()); + cfg.flag(&flag); + } + cfg.file("../rustllvm/ExecutionEngineWrapper.cpp") .file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 4df2da801f9..f28935fbcc2 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -2013,6 +2013,9 @@ extern { pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); + pub fn LLVMRustHasFeature(T: TargetMachineRef, + s: *const c_char) -> bool; + pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, CPU: *const c_char, Features: *const c_char, diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index d6985719acb..b3d4e35d7b0 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -97,6 +97,75 @@ LLVMRustAddPass(LLVMPassManagerRef PM, Pass *pass) { pm->add(pass); } +#ifdef LLVM_COMPONENT_X86 +#define SUBTARGET_X86 SUBTARGET(X86) +#else +#define SUBTARGET_X86 +#endif + +#ifdef LLVM_COMPONENT_ARM +#define SUBTARGET_ARM SUBTARGET(ARM) +#else +#define SUBTARGET_ARM +#endif + +#ifdef LLVM_COMPONENT_AARCH64 +#define SUBTARGET_AARCH64 SUBTARGET(AArch64) +#else +#define SUBTARGET_AARCH64 +#endif + +#ifdef LLVM_COMPONENT_MIPS +#define SUBTARGET_MIPS SUBTARGET(Mips) +#else +#define SUBTARGET_MIPS +#endif + +#ifdef LLVM_COMPONENT_POWERPC +#define SUBTARGET_PPC SUBTARGET(PPC) +#else +#define SUBTARGET_PPC +#endif + +#define GEN_SUBTARGETS \ + SUBTARGET_X86 \ + SUBTARGET_ARM \ + SUBTARGET_AARCH64 \ + SUBTARGET_MIPS \ + SUBTARGET_PPC + +#define SUBTARGET(x) namespace llvm { \ + extern const SubtargetFeatureKV x##FeatureKV[]; \ + extern const SubtargetFeatureKV x##SubTypeKV[]; \ + } + +GEN_SUBTARGETS +#undef SUBTARGET + +extern "C" bool +LLVMRustHasFeature(LLVMTargetMachineRef TM, + const char *feature) { + TargetMachine *Target = unwrap(TM); + const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); + const FeatureBitset &Bits = MCInfo->getFeatureBits(); + const llvm::SubtargetFeatureKV *FeatureEntry; + +#define SUBTARGET(x) \ + if (MCInfo->isCPUStringValid(x##SubTypeKV[0].Key)) { \ + FeatureEntry = x##FeatureKV; \ + } else + + GEN_SUBTARGETS { + return false; + } +#undef SUBTARGET + + while (strcmp(feature, FeatureEntry->Key) != 0) + FeatureEntry++; + + return (Bits & FeatureEntry->Value) == FeatureEntry->Value; +} + extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(const char *triple, const char *cpu, From 92e24b95167897881377d43ce3ee6aa7ba2685a4 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Tue, 16 Feb 2016 17:09:17 +0100 Subject: [PATCH 03/10] Expose the features computed from LLVM in `cfg!` Instead of relying on the features explicitly passed through the command line, compute them from the LLVM `TargetMachine`. --- src/librustc_driver/target_features.rs | 98 +++++++++----------------- 1 file changed, 33 insertions(+), 65 deletions(-) diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 27ffb595a40..7c3c7b2e7b6 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -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 target_machine = create_target_machine(sess); + + let arm_whitelist = [ + "neon\0", + "vfp\0", + ]; + + let x86_whitelist = [ + "avx\0", + "avx2\0", + "sse\0", + "sse2\0", + "sse3\0", + "sse4.1\0", + "sse4.2\0", + "ssse3\0", + ]; + + let whitelist = match &*sess.target.target.arch { + "arm" => &arm_whitelist[..], + "x86" | "x86_64" => &x86_whitelist[..], + _ => &[][..], + }; + 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"; + 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))) + } } } - - -fn features_contain(sess: &Session, s: &str) -> bool { - sess.target.target.options.features.contains(s) || sess.opts.cg.target_feature.contains(s) -} - -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") -} - -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") -} From 358e41cee4c31a739b6a45723e8917b19e7f7db9 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 2 Mar 2016 21:02:12 +0100 Subject: [PATCH 04/10] Introduce the `init_llvm` function Extract the code that performs the initialization of the LLVM backend and invoke it before computing the available features. The initialization is required to happen before the features are added to the configuration, because they are computed by LLVM, therefore is is now performed when creating the `Session` object. --- src/librustc/session/mod.rs | 57 ++++++++++++++++++++++++++++++++ src/librustc_trans/back/write.rs | 32 +----------------- src/librustc_trans/base.rs | 20 ----------- 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index d3005ff2ded..dfde3ded46d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -30,13 +30,16 @@ use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; use rustc_back::target::Target; +use llvm; use std::path::{Path, PathBuf}; use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; +use std::ffi::CString; use std::rc::Rc; use std::fmt; +use libc::c_int; pub mod config; pub mod filesearch; @@ -491,9 +494,63 @@ pub fn build_session_(sopts: config::Options, imported_macro_spans: RefCell::new(HashMap::new()), }; + init_llvm(&sess); + sess } +fn init_llvm(sess: &Session) { + unsafe { + // Before we touch LLVM, make sure that multithreading is enabled. + use std::sync::Once; + static INIT: Once = Once::new(); + static mut POISONED: bool = false; + 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 = true; + } + + configure_llvm(sess); + }); + + if POISONED { + 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"); } + + // FIXME #21627 disable faulty FastISel on AArch64 (even for -O0) + if sess.target.target.arch == "aarch64" { add("-fast-isel=0"); } + + 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()); +} + pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let mut emitter: Box = match output { config::ErrorOutputType::HumanReadable(color_config) => { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index e6a51eb7c87..8a915f04405 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -31,7 +31,7 @@ use std::str; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{c_uint, c_int, c_void}; +use libc::{c_uint, c_void}; pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! { match llvm::last_error() { @@ -984,36 +984,6 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { } } -pub 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"); } - - // FIXME #21627 disable faulty FastISel on AArch64 (even for -O0) - if sess.target.target.arch == "aarch64" { add("-fast-isel=0"); } - - 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()); -} - pub unsafe fn with_llvm_pmb(llmod: ModuleRef, config: &ModuleConfig, f: &mut FnMut(llvm::PassManagerBuilderRef)) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 17230eff6e6..6304a0eacd3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2709,26 +2709,6 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, tcx.sess.opts.debug_assertions }; - // Before we touch LLVM, make sure that multithreading is enabled. - unsafe { - use std::sync::Once; - static INIT: Once = Once::new(); - static mut POISONED: bool = false; - 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 = true; - } - - ::back::write::configure_llvm(&tcx.sess); - }); - - if POISONED { - bug!("couldn't enable multi-threaded LLVM"); - } - } - let link_meta = link::build_link_meta(&tcx, name); let codegen_units = tcx.sess.opts.cg.codegen_units; From 3fc5d2746eb9ded7a43186f6e2e0b3bd3e8ffd42 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 30 Mar 2016 11:37:41 +0200 Subject: [PATCH 05/10] Test target feature computation --- src/test/run-make/print-cfg/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-make/print-cfg/Makefile b/src/test/run-make/print-cfg/Makefile index c74233d495b..a820a463f4a 100644 --- a/src/test/run-make/print-cfg/Makefile +++ b/src/test/run-make/print-cfg/Makefile @@ -5,6 +5,7 @@ all: default $(RUSTC) --target x86_64-pc-windows-gnu --print cfg | grep x86_64 $(RUSTC) --target i686-pc-windows-msvc --print cfg | grep msvc $(RUSTC) --target i686-apple-darwin --print cfg | grep macos + $(RUSTC) --target i686-unknown-linux-gnu --print cfg | grep sse2 ifdef IS_WINDOWS default: From f942c28900159152358dd2f5718262464c09dc52 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sun, 10 Apr 2016 14:21:00 +0200 Subject: [PATCH 06/10] Do not intern NUL terminators The C representation needed by LLVM requires strings to be NUL-terminated, but on the Rust side they should not contain unwanted NULs. --- src/librustc_driver/target_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 7c3c7b2e7b6..7f4375e993d 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -49,7 +49,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { 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))) + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len()-1]))) } } } From 5879ee1ecaa5738d93613c7bd14bdd09ab48450d Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Thu, 14 Apr 2016 13:02:47 +0200 Subject: [PATCH 07/10] Distinguish different `vfp?` features The different generations of ARM floating point VFP correspond to the LLVM CPU features named `vfp2`, `vfp3`, and `vfp4`; they are now exposed in Rust under the same names. This commit fixes some crashes that would occour when checking if the `vfp` feature exists (the crash occurs because the linear scan of the LLVM feature goes past the end of the features whenever it searches for a feature that does not exist in the LLVM tables). --- src/librustc_driver/target_features.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 7f4375e993d..73b2b85a352 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -24,9 +24,15 @@ use libc::c_char; pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { let target_machine = create_target_machine(sess); + // WARNING: the features must be known to LLVM or the feature + // detection code will walk past the end of the feature array, + // leading to crashes. + let arm_whitelist = [ "neon\0", - "vfp\0", + "vfp2\0", + "vfp3\0", + "vfp4\0", ]; let x86_whitelist = [ From 1ad85610e4eae8b7281c85186dff8edb23b5d21c Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Tue, 19 Apr 2016 18:37:39 +0200 Subject: [PATCH 08/10] Add test for `target_feature` This test checks that all of the x86 architectures (both `x86` and `x86_64`) have the `sse2` feature. This is currently true for all of the targets whose target CPU is `pentium4` (or better), but it might fail on other targets (for example on `i586`). --- src/test/run-pass/sse2.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/run-pass/sse2.rs diff --git a/src/test/run-pass/sse2.rs b/src/test/run-pass/sse2.rs new file mode 100644 index 00000000000..78d91b2f312 --- /dev/null +++ b/src/test/run-pass/sse2.rs @@ -0,0 +1,18 @@ +// Copyright 2012-2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(cfg_target_feature)] + +pub fn main() { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + assert!(cfg!(target_feature = "sse2"), + "SSE2 was not detected as available on an x86 platform"); + } +} From deaa2fe7536e395a890f910019a820b36f2cd992 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 20 Apr 2016 09:08:25 +0200 Subject: [PATCH 09/10] Make the feature whitelists constants This simplifies the code a bit and makes the types nicer, too. --- src/librustc_driver/target_features.rs | 50 +++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 73b2b85a352..69d146059c9 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -16,6 +16,28 @@ use syntax::parse::token::InternedString; use syntax::parse::token::intern_and_get_ident as intern; use libc::c_char; +// WARNING: the features 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\0", + "vfp2\0", + "vfp3\0", + "vfp4\0", +]; + +const X86_WHITELIST: &'static [&'static str] = &[ + "avx\0", + "avx2\0", + "sse\0", + "sse2\0", + "sse3\0", + "sse4.1\0", + "sse4.2\0", + "ssse3\0", +]; + /// Add `target_feature = "..."` cfgs for a variety of platform /// specific features (SSE, NEON etc.). /// @@ -24,32 +46,10 @@ use libc::c_char; pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { let target_machine = create_target_machine(sess); - // WARNING: the features must be known to LLVM or the feature - // detection code will walk past the end of the feature array, - // leading to crashes. - - let arm_whitelist = [ - "neon\0", - "vfp2\0", - "vfp3\0", - "vfp4\0", - ]; - - let x86_whitelist = [ - "avx\0", - "avx2\0", - "sse\0", - "sse2\0", - "sse3\0", - "sse4.1\0", - "sse4.2\0", - "ssse3\0", - ]; - let whitelist = match &*sess.target.target.arch { - "arm" => &arm_whitelist[..], - "x86" | "x86_64" => &x86_whitelist[..], - _ => &[][..], + "arm" => ARM_WHITELIST, + "x86" | "x86_64" => X86_WHITELIST, + _ => &[], }; let tf = InternedString::new("target_feature"); From ce99a5e5d8ead9140bb9b48c01f1a200950f8ea3 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 20 Apr 2016 09:09:30 +0200 Subject: [PATCH 10/10] Check that the feature strings are well-formed Assert that the feature strings are NUL terminated, so that they will be well-formed as C strings. This is a safety check to ease the maintaninace and update of the feature lists. --- src/librustc_driver/target_features.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index 69d146059c9..fad0af19a12 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -54,6 +54,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { let tf = InternedString::new("target_feature"); for feat in whitelist { + assert_eq!(feat.chars().last(), Some('\0')); if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } { cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len()-1]))) }