add dedicated type for ABI target feature constraints
This commit is contained in:
parent
43ede97ebf
commit
2e64b5352b
5 changed files with 45 additions and 31 deletions
|
@ -47,9 +47,9 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||||
|
|
||||||
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||||
// are disabled.
|
// are disabled.
|
||||||
let (abi_enable, abi_disable) = sess.target.abi_required_features();
|
let abi_feature_constraints = sess.target.abi_required_features();
|
||||||
let abi_enable_set = FxHashSet::from_iter(abi_enable.iter().copied());
|
let abi_incompatible_set =
|
||||||
let abi_disable_set = FxHashSet::from_iter(abi_disable.iter().copied());
|
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
|
||||||
|
|
||||||
// Compute implied features
|
// Compute implied features
|
||||||
let mut all_rust_features = vec![];
|
let mut all_rust_features = vec![];
|
||||||
|
@ -72,7 +72,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove features that are meant for rustc, not LLVM.
|
// Remove features that are meant for rustc, not codegen.
|
||||||
all_rust_features.retain(|(_, feature)| {
|
all_rust_features.retain(|(_, feature)| {
|
||||||
// Retain if it is not a rustc feature
|
// Retain if it is not a rustc feature
|
||||||
!RUSTC_SPECIFIC_FEATURES.contains(feature)
|
!RUSTC_SPECIFIC_FEATURES.contains(feature)
|
||||||
|
@ -121,7 +121,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||||
|
|
||||||
// Ensure that the features we enable/disable are compatible with the ABI.
|
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||||
if enable {
|
if enable {
|
||||||
if abi_disable_set.contains(feature) {
|
if abi_incompatible_set.contains(feature) {
|
||||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||||
feature,
|
feature,
|
||||||
enabled: "enabled",
|
enabled: "enabled",
|
||||||
|
@ -131,8 +131,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||||
} else {
|
} else {
|
||||||
// FIXME: we have to request implied features here since
|
// FIXME: we have to request implied features here since
|
||||||
// negative features do not handle implied features above.
|
// negative features do not handle implied features above.
|
||||||
#[allow(rustc::potential_query_instability)] // order does not matter
|
for &required in abi_feature_constraints.required.iter() {
|
||||||
for &required in abi_enable_set.iter() {
|
|
||||||
let implied = sess.target.implied_target_features(std::iter::once(required));
|
let implied = sess.target.implied_target_features(std::iter::once(required));
|
||||||
if implied.contains(feature) {
|
if implied.contains(feature) {
|
||||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||||
|
@ -158,7 +157,11 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||||
// still override it... that's unsound, but more compatible with past behavior.
|
// still override it... that's unsound, but more compatible with past behavior.
|
||||||
all_rust_features.splice(
|
all_rust_features.splice(
|
||||||
0..0,
|
0..0,
|
||||||
abi_enable.iter().map(|&f| (true, f)).chain(abi_disable.iter().map(|&f| (false, f))),
|
abi_feature_constraints
|
||||||
|
.required
|
||||||
|
.iter()
|
||||||
|
.map(|&f| (true, f))
|
||||||
|
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Translate this into GCC features.
|
// Translate this into GCC features.
|
||||||
|
|
|
@ -669,9 +669,9 @@ pub(crate) fn global_llvm_features(
|
||||||
|
|
||||||
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||||
// are disabled.
|
// are disabled.
|
||||||
let (abi_enable, abi_disable) = sess.target.abi_required_features();
|
let abi_feature_constraints = sess.target.abi_required_features();
|
||||||
let abi_enable_set = FxHashSet::from_iter(abi_enable.iter().copied());
|
let abi_incompatible_set =
|
||||||
let abi_disable_set = FxHashSet::from_iter(abi_disable.iter().copied());
|
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
|
||||||
|
|
||||||
// Compute implied features
|
// Compute implied features
|
||||||
let mut all_rust_features = vec![];
|
let mut all_rust_features = vec![];
|
||||||
|
@ -745,7 +745,7 @@ pub(crate) fn global_llvm_features(
|
||||||
|
|
||||||
// Ensure that the features we enable/disable are compatible with the ABI.
|
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||||
if enable {
|
if enable {
|
||||||
if abi_disable_set.contains(feature) {
|
if abi_incompatible_set.contains(feature) {
|
||||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||||
feature,
|
feature,
|
||||||
enabled: "enabled",
|
enabled: "enabled",
|
||||||
|
@ -755,8 +755,7 @@ pub(crate) fn global_llvm_features(
|
||||||
} else {
|
} else {
|
||||||
// FIXME: we have to request implied features here since
|
// FIXME: we have to request implied features here since
|
||||||
// negative features do not handle implied features above.
|
// negative features do not handle implied features above.
|
||||||
#[allow(rustc::potential_query_instability)] // order does not matter
|
for &required in abi_feature_constraints.required.iter() {
|
||||||
for &required in abi_enable_set.iter() {
|
|
||||||
let implied =
|
let implied =
|
||||||
sess.target.implied_target_features(std::iter::once(required));
|
sess.target.implied_target_features(std::iter::once(required));
|
||||||
if implied.contains(feature) {
|
if implied.contains(feature) {
|
||||||
|
@ -783,7 +782,11 @@ pub(crate) fn global_llvm_features(
|
||||||
// still override it... that's unsound, but more compatible with past behavior.
|
// still override it... that's unsound, but more compatible with past behavior.
|
||||||
all_rust_features.splice(
|
all_rust_features.splice(
|
||||||
0..0,
|
0..0,
|
||||||
abi_enable.iter().map(|&f| (true, f)).chain(abi_disable.iter().map(|&f| (false, f))),
|
abi_feature_constraints
|
||||||
|
.required
|
||||||
|
.iter()
|
||||||
|
.map(|&f| (true, f))
|
||||||
|
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Translate this into LLVM features.
|
// Translate this into LLVM features.
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub(crate) fn from_target_feature_attr(
|
||||||
.emit();
|
.emit();
|
||||||
};
|
};
|
||||||
let rust_features = tcx.features();
|
let rust_features = tcx.features();
|
||||||
let (_abi_enable, abi_disable) = tcx.sess.target.abi_required_features();
|
let abi_feature_constraints = tcx.sess.target.abi_required_features();
|
||||||
for item in list {
|
for item in list {
|
||||||
// Only `enable = ...` is accepted in the meta-item list.
|
// Only `enable = ...` is accepted in the meta-item list.
|
||||||
if !item.has_name(sym::enable) {
|
if !item.has_name(sym::enable) {
|
||||||
|
@ -87,7 +87,7 @@ pub(crate) fn from_target_feature_attr(
|
||||||
// But ensure the ABI does not forbid enabling this.
|
// But ensure the ABI does not forbid enabling this.
|
||||||
// Here we do assume that LLVM doesn't add even more implied features
|
// Here we do assume that LLVM doesn't add even more implied features
|
||||||
// we don't know about, at least no features that would have ABI effects!
|
// we don't know about, at least no features that would have ABI effects!
|
||||||
if abi_disable.contains(&name.as_str()) {
|
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
|
||||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||||
span: item.span(),
|
span: item.span(),
|
||||||
feature: name.as_str(),
|
feature: name.as_str(),
|
||||||
|
|
|
@ -3242,8 +3242,8 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check that we don't mis-set any of the ABI-relevant features.
|
// Check that we don't mis-set any of the ABI-relevant features.
|
||||||
let (abi_enable, abi_disable) = self.abi_required_features();
|
let abi_feature_constraints = self.abi_required_features();
|
||||||
for feat in abi_enable {
|
for feat in abi_feature_constraints.required {
|
||||||
// The feature might be enabled by default so we can't *require* it to show up.
|
// The feature might be enabled by default so we can't *require* it to show up.
|
||||||
// But it must not be *disabled*.
|
// But it must not be *disabled*.
|
||||||
if features_disabled.contains(feat) {
|
if features_disabled.contains(feat) {
|
||||||
|
@ -3252,8 +3252,8 @@ impl Target {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for feat in abi_disable {
|
for feat in abi_feature_constraints.incompatible {
|
||||||
// The feature might be disable by default so we can't *require* it to show up.
|
// The feature might be disabled by default so we can't *require* it to show up.
|
||||||
// But it must not be *enabled*.
|
// But it must not be *enabled*.
|
||||||
if features_enabled.contains(feat) {
|
if features_enabled.contains(feat) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
|
|
|
@ -669,6 +669,14 @@ const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(
|
||||||
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||||
&[(128, "lsx"), (256, "lasx")];
|
&[(128, "lsx"), (256, "lasx")];
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct FeatureConstraints {
|
||||||
|
/// Features that must be enabled.
|
||||||
|
pub required: &'static [&'static str],
|
||||||
|
/// Features that must be disabled.
|
||||||
|
pub incompatible: &'static [&'static str],
|
||||||
|
}
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
||||||
match &*self.arch {
|
match &*self.arch {
|
||||||
|
@ -749,8 +757,8 @@ impl Target {
|
||||||
/// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked
|
/// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked
|
||||||
/// against this. We also check any implied features, based on the information above. If LLVM
|
/// against this. We also check any implied features, based on the information above. If LLVM
|
||||||
/// implicitly enables more implied features than we do, that could bypass this check!
|
/// implicitly enables more implied features than we do, that could bypass this check!
|
||||||
pub fn abi_required_features(&self) -> (&'static [&'static str], &'static [&'static str]) {
|
pub fn abi_required_features(&self) -> FeatureConstraints {
|
||||||
const NOTHING: (&'static [&'static str], &'static [&'static str]) = (&[], &[]);
|
const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] };
|
||||||
// Some architectures don't have a clean explicit ABI designation; instead, the ABI is
|
// Some architectures don't have a clean explicit ABI designation; instead, the ABI is
|
||||||
// defined by target features. When that is the case, those target features must be
|
// defined by target features. When that is the case, those target features must be
|
||||||
// "forbidden" in the list above to ensure that there is a consistent answer to the
|
// "forbidden" in the list above to ensure that there is a consistent answer to the
|
||||||
|
@ -763,7 +771,7 @@ impl Target {
|
||||||
NOTHING
|
NOTHING
|
||||||
} else {
|
} else {
|
||||||
// Hardfloat ABI. x87 must be enabled.
|
// Hardfloat ABI. x87 must be enabled.
|
||||||
(&["x87"], &[])
|
FeatureConstraints { required: &["x87"], incompatible: &[] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"x86_64" => {
|
"x86_64" => {
|
||||||
|
@ -773,7 +781,7 @@ impl Target {
|
||||||
NOTHING
|
NOTHING
|
||||||
} else {
|
} else {
|
||||||
// Hardfloat ABI. x87 and SSE2 must be enabled.
|
// Hardfloat ABI. x87 and SSE2 must be enabled.
|
||||||
(&["x87", "sse2"], &[])
|
FeatureConstraints { required: &["x87", "sse2"], incompatible: &[] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"arm" => {
|
"arm" => {
|
||||||
|
@ -786,7 +794,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
FloatAbi::Hard => {
|
FloatAbi::Hard => {
|
||||||
// Must have `fpregs` and must not have `soft-float`.
|
// Must have `fpregs` and must not have `soft-float`.
|
||||||
(&["fpregs"], &["soft-float"])
|
FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -803,7 +811,7 @@ impl Target {
|
||||||
_ => {
|
_ => {
|
||||||
// Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
|
// Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
|
||||||
// These are Rust feature names and we use "neon" to control both of them.
|
// These are Rust feature names and we use "neon" to control both of them.
|
||||||
(&["neon"], &[])
|
FeatureConstraints { required: &["neon"], incompatible: &[] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,15 +821,15 @@ impl Target {
|
||||||
match &*self.llvm_abiname {
|
match &*self.llvm_abiname {
|
||||||
"ilp32d" | "lp64d" => {
|
"ilp32d" | "lp64d" => {
|
||||||
// Requires d (which implies f), incompatible with e.
|
// Requires d (which implies f), incompatible with e.
|
||||||
(&["d"], &["e"])
|
FeatureConstraints { required: &["d"], incompatible: &["e"] }
|
||||||
}
|
}
|
||||||
"ilp32f" | "lp64f" => {
|
"ilp32f" | "lp64f" => {
|
||||||
// Requires f, incompatible with e.
|
// Requires f, incompatible with e.
|
||||||
(&["f"], &["e"])
|
FeatureConstraints { required: &["f"], incompatible: &["e"] }
|
||||||
}
|
}
|
||||||
"ilp32" | "lp64" => {
|
"ilp32" | "lp64" => {
|
||||||
// Requires nothing, incompatible with e.
|
// Requires nothing, incompatible with e.
|
||||||
(&[], &["e"])
|
FeatureConstraints { required: &[], incompatible: &["e"] }
|
||||||
}
|
}
|
||||||
"ilp32e" => {
|
"ilp32e" => {
|
||||||
// ilp32e is documented to be incompatible with features that need aligned
|
// ilp32e is documented to be incompatible with features that need aligned
|
||||||
|
@ -832,7 +840,7 @@ impl Target {
|
||||||
// Note that the `e` feature is not required: the ABI treats the extra
|
// Note that the `e` feature is not required: the ABI treats the extra
|
||||||
// registers as caller-save, so it is safe to use them only in some parts of
|
// registers as caller-save, so it is safe to use them only in some parts of
|
||||||
// a program while the rest doesn't know they even exist.
|
// a program while the rest doesn't know they even exist.
|
||||||
(&[], &["d"])
|
FeatureConstraints { required: &[], incompatible: &["d"] }
|
||||||
}
|
}
|
||||||
"lp64e" => {
|
"lp64e" => {
|
||||||
// As above, `e` is not required.
|
// As above, `e` is not required.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue