Change signature of target_features_cfg
.
Currently it is called twice, once with `allow_unstable` set to true and once with it set to false. This results in some duplicated work. Most notably, for the LLVM backend, `LLVMRustHasFeature` is called twice for every feature, and it's moderately slow. For very short running compilations on platforms with many features (e.g. a `check` build of hello-world on x86) this is a significant fraction of runtime. This commit changes `target_features_cfg` so it is only called once, and it now returns a pair of feature sets. This halves the number of `LLVMRustHasFeature` calls.
This commit is contained in:
parent
2df8e657f2
commit
936a8232df
6 changed files with 85 additions and 71 deletions
|
@ -176,13 +176,9 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_features_cfg(
|
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||||
&self,
|
|
||||||
sess: &Session,
|
|
||||||
_allow_unstable: bool,
|
|
||||||
) -> Vec<rustc_span::Symbol> {
|
|
||||||
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
||||||
if sess.target.arch == "x86_64" && sess.target.os != "none" {
|
let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" {
|
||||||
// x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
|
// x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
|
||||||
vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")]
|
vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")]
|
||||||
} else if sess.target.arch == "aarch64" {
|
} else if sess.target.arch == "aarch64" {
|
||||||
|
@ -196,7 +192,10 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
};
|
||||||
|
// FIXME do `unstable_target_features` properly
|
||||||
|
let unstable_target_features = target_features.clone();
|
||||||
|
(target_features, unstable_target_features)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_version(&self) {
|
fn print_version(&self) {
|
||||||
|
|
|
@ -259,8 +259,8 @@ impl CodegenBackend for GccCodegenBackend {
|
||||||
.join(sess)
|
.join(sess)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||||
target_features_cfg(sess, allow_unstable, &self.target_info)
|
target_features_cfg(sess, &self.target_info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,16 +486,17 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
||||||
/// Returns the features that should be set in `cfg(target_feature)`.
|
/// Returns the features that should be set in `cfg(target_feature)`.
|
||||||
fn target_features_cfg(
|
fn target_features_cfg(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
allow_unstable: bool,
|
|
||||||
target_info: &LockedTargetInfo,
|
target_info: &LockedTargetInfo,
|
||||||
) -> Vec<Symbol> {
|
) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||||
// TODO(antoyo): use global_gcc_features.
|
// TODO(antoyo): use global_gcc_features.
|
||||||
|
let f = |allow_unstable| {
|
||||||
sess.target
|
sess.target
|
||||||
.rust_target_features()
|
.rust_target_features()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&(feature, gate, _)| {
|
.filter_map(|&(feature, gate, _)| {
|
||||||
if allow_unstable
|
if allow_unstable
|
||||||
|| (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
|| (gate.in_cfg()
|
||||||
|
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||||
{
|
{
|
||||||
Some(feature)
|
Some(feature)
|
||||||
} else {
|
} else {
|
||||||
|
@ -517,4 +518,9 @@ fn target_features_cfg(
|
||||||
})
|
})
|
||||||
.map(Symbol::intern)
|
.map(Symbol::intern)
|
||||||
.collect()
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_features = f(false);
|
||||||
|
let unstable_target_features = f(true);
|
||||||
|
(target_features, unstable_target_features)
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,8 +338,8 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||||
llvm_util::print_version();
|
llvm_util::print_version();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||||
target_features_cfg(sess, allow_unstable)
|
target_features_cfg(sess)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn codegen_crate<'tcx>(
|
fn codegen_crate<'tcx>(
|
||||||
|
|
|
@ -306,7 +306,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
||||||
/// Must express features in the way Rust understands them.
|
/// Must express features in the way Rust understands them.
|
||||||
///
|
///
|
||||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
||||||
pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||||
let mut features: FxHashSet<Symbol> = Default::default();
|
let mut features: FxHashSet<Symbol> = Default::default();
|
||||||
|
|
||||||
// Add base features for the target.
|
// Add base features for the target.
|
||||||
|
@ -331,6 +331,9 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
|
||||||
if let Some(feat) = to_llvm_features(sess, feature) {
|
if let Some(feat) = to_llvm_features(sess, feature) {
|
||||||
for llvm_feature in feat {
|
for llvm_feature in feat {
|
||||||
let cstr = SmallCStr::new(llvm_feature);
|
let cstr = SmallCStr::new(llvm_feature);
|
||||||
|
// `LLVMRustHasFeature` is moderately expensive. On targets with many
|
||||||
|
// features (e.g. x86) these calls take a non-trivial fraction of runtime
|
||||||
|
// when compiling very small programs.
|
||||||
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) }
|
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) }
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -371,11 +374,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
|
||||||
// `features.contains` below.
|
// `features.contains` below.
|
||||||
#[allow(rustc::potential_query_instability)]
|
#[allow(rustc::potential_query_instability)]
|
||||||
features.retain(|f| {
|
features.retain(|f| {
|
||||||
if sess
|
if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
|
||||||
.target
|
|
||||||
.implied_target_features(f.as_str())
|
|
||||||
.contains(&feature.as_str())
|
|
||||||
{
|
|
||||||
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
|
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
|
||||||
// remove `f`. (This is the standard logical contraposition principle.)
|
// remove `f`. (This is the standard logical contraposition principle.)
|
||||||
false
|
false
|
||||||
|
@ -387,16 +386,18 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter enabled features based on feature gates
|
// Filter enabled features based on feature gates.
|
||||||
|
let f = |allow_unstable| {
|
||||||
sess.target
|
sess.target
|
||||||
.rust_target_features()
|
.rust_target_features()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(feature, gate, _)| {
|
.filter_map(|(feature, gate, _)| {
|
||||||
// The `allow_unstable` set is used by rustc internally to determined which target
|
// The `allow_unstable` set is used by rustc internally to determined which target
|
||||||
// features are truly available, so we want to return even perma-unstable "forbidden"
|
// features are truly available, so we want to return even perma-unstable
|
||||||
// features.
|
// "forbidden" features.
|
||||||
if allow_unstable
|
if allow_unstable
|
||||||
|| (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
|| (gate.in_cfg()
|
||||||
|
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||||
{
|
{
|
||||||
Some(Symbol::intern(feature))
|
Some(Symbol::intern(feature))
|
||||||
} else {
|
} else {
|
||||||
|
@ -405,6 +406,11 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
|
||||||
})
|
})
|
||||||
.filter(|feature| features.contains(&feature))
|
.filter(|feature| features.contains(&feature))
|
||||||
.collect()
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_features = f(false);
|
||||||
|
let unstable_target_features = f(true);
|
||||||
|
(target_features, unstable_target_features)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_version() {
|
pub(crate) fn print_version() {
|
||||||
|
|
|
@ -45,10 +45,13 @@ pub trait CodegenBackend {
|
||||||
|
|
||||||
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
|
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
|
||||||
|
|
||||||
/// Returns the features that should be set in `cfg(target_features)`.
|
/// Returns two feature sets:
|
||||||
|
/// - The first has the features that should be set in `cfg(target_features)`.
|
||||||
|
/// - The second is like the first, but also includes unstable features.
|
||||||
|
///
|
||||||
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
|
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
|
||||||
fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
|
fn target_features_cfg(&self, _sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||||
vec![]
|
(vec![], vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_passes(&self) {}
|
fn print_passes(&self) {}
|
||||||
|
|
|
@ -39,11 +39,11 @@ pub(crate) fn add_configuration(
|
||||||
) {
|
) {
|
||||||
let tf = sym::target_feature;
|
let tf = sym::target_feature;
|
||||||
|
|
||||||
let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
|
let (target_features, unstable_target_features) = codegen_backend.target_features_cfg(sess);
|
||||||
sess.unstable_target_features.extend(unstable_target_features.iter().cloned());
|
|
||||||
|
|
||||||
let target_features = codegen_backend.target_features_cfg(sess, false);
|
sess.unstable_target_features.extend(unstable_target_features.iter().copied());
|
||||||
sess.target_features.extend(target_features.iter().cloned());
|
|
||||||
|
sess.target_features.extend(target_features.iter().copied());
|
||||||
|
|
||||||
cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
|
cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue