Skip to content

Commit b4aa986

Browse files
committed
Don't use LLVM to compute -Ctarget-feature
1 parent 2f890e7 commit b4aa986

File tree

6 files changed

+120
-112
lines changed

6 files changed

+120
-112
lines changed

compiler/rustc_codegen_llvm/src/back/write.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,12 @@ pub fn write_output_file<'ll>(
9797

9898
pub fn create_informational_target_machine(
9999
sess: &Session,
100-
extra_features: bool,
100+
only_base_features: bool,
101101
) -> OwnedTargetMachine {
102102
let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
103103
// Can't use query system here quite yet because this function is invoked before the query
104104
// system/tcx is set up.
105-
let features =
106-
if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() };
105+
let features = llvm_util::global_llvm_features(sess, false, only_base_features);
107106
target_machine_factory(sess, config::OptLevel::No, &features)(config)
108107
.unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
109108
}

compiler/rustc_codegen_llvm/src/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>(
149149

150150
// Ensure the data-layout values hardcoded remain the defaults.
151151
{
152-
let tm = crate::back::write::create_informational_target_machine(tcx.sess, true);
152+
let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
153153
unsafe {
154154
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
155155
}

compiler/rustc_codegen_llvm/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ impl CodegenBackend for LlvmCodegenBackend {
269269

270270
fn provide(&self, providers: &mut Providers) {
271271
providers.global_backend_features =
272-
|tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
272+
|tcx, ()| llvm_util::global_llvm_features(tcx.sess, true, false)
273273
}
274274

275275
fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
@@ -434,7 +434,7 @@ impl ModuleLlvm {
434434
ModuleLlvm {
435435
llmod_raw,
436436
llcx,
437-
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, true)),
437+
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
438438
}
439439
}
440440
}

compiler/rustc_codegen_llvm/src/llvm_util.rs

+107-104
Original file line numberDiff line numberDiff line change
@@ -308,19 +308,10 @@ pub fn check_tied_features(
308308
/// Used to generate cfg variables and apply features
309309
/// Must express features in the way Rust understands them
310310
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
311-
let rust_features = sess
312-
.target
313-
.supported_target_features()
314-
.iter()
315-
.map(|(feature, _, _)| {
316-
(to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature))
317-
})
318-
.collect::<FxHashMap<_, _>>();
319-
320311
let mut features = FxHashSet::default();
321312

322313
// Add base features for the target
323-
let target_machine = create_informational_target_machine(sess, false);
314+
let target_machine = create_informational_target_machine(sess, true);
324315
features.extend(
325316
sess.target
326317
.supported_target_features()
@@ -343,13 +334,16 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
343334
);
344335

345336
// Add enabled features
346-
for llvm_feature in global_llvm_features(sess, false) {
347-
let (add, llvm_feature) = llvm_feature.split_at(1);
348-
let feature =
349-
rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature));
350-
if add == "+" {
337+
for (enabled, feature) in
338+
sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
339+
Some('+') => Some((true, Symbol::intern(&s[1..]))),
340+
Some('-') => Some((false, Symbol::intern(&s[1..]))),
341+
_ => None,
342+
})
343+
{
344+
if enabled {
351345
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
352-
} else if add == "-" {
346+
} else {
353347
features.remove(&feature);
354348
}
355349
}
@@ -475,7 +469,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
475469

476470
pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
477471
require_inited();
478-
let tm = create_informational_target_machine(sess, true);
472+
let tm = create_informational_target_machine(sess, false);
479473
match req.kind {
480474
PrintKind::TargetCPUs => {
481475
// SAFETY generate a C compatible string from a byte slice to pass
@@ -523,7 +517,11 @@ pub fn target_cpu(sess: &Session) -> &str {
523517

524518
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
525519
/// `--target` and similar).
526-
pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<String> {
520+
pub(crate) fn global_llvm_features(
521+
sess: &Session,
522+
diagnostics: bool,
523+
only_base_features: bool,
524+
) -> Vec<String> {
527525
// Features that come earlier are overridden by conflicting features later in the string.
528526
// Typically we'll want more explicit settings to override the implicit ones, so:
529527
//
@@ -583,96 +581,109 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
583581
}
584582

585583
// -Ctarget-features
586-
let supported_features = sess.target.supported_target_features();
587-
let (llvm_major, _, _) = get_version();
588-
let mut featsmap = FxHashMap::default();
589-
let feats = sess
590-
.opts
591-
.cg
592-
.target_feature
593-
.split(',')
594-
.filter_map(|s| {
595-
let enable_disable = match s.chars().next() {
596-
None => return None,
597-
Some(c @ ('+' | '-')) => c,
598-
Some(_) => {
599-
if diagnostics {
600-
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
584+
if !only_base_features {
585+
let supported_features = sess.target.supported_target_features();
586+
let (llvm_major, _, _) = get_version();
587+
let mut featsmap = FxHashMap::default();
588+
let feats = sess
589+
.opts
590+
.cg
591+
.target_feature
592+
.split(',')
593+
.filter_map(|s| {
594+
let enable_disable = match s.chars().next() {
595+
None => return None,
596+
Some(c @ ('+' | '-')) => c,
597+
Some(_) => {
598+
if diagnostics {
599+
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
600+
}
601+
return None;
601602
}
602-
return None;
603-
}
604-
};
603+
};
605604

606-
let feature = backend_feature_name(sess, s)?;
607-
// Warn against use of LLVM specific feature names and unstable features on the CLI.
608-
if diagnostics {
609-
let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
610-
if feature_state.is_none() {
611-
let rust_feature =
612-
supported_features.iter().find_map(|&(rust_feature, _, _)| {
613-
let llvm_features = to_llvm_features(sess, rust_feature);
614-
if llvm_features.contains(feature)
615-
&& !llvm_features.contains(rust_feature)
616-
{
617-
Some(rust_feature)
618-
} else {
619-
None
605+
let feature = backend_feature_name(sess, s)?;
606+
// Warn against use of LLVM specific feature names and unstable features on the CLI.
607+
if diagnostics {
608+
let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
609+
if feature_state.is_none() {
610+
let rust_feature =
611+
supported_features.iter().find_map(|&(rust_feature, _, _)| {
612+
let llvm_features = to_llvm_features(sess, rust_feature);
613+
if llvm_features.contains(feature)
614+
&& !llvm_features.contains(rust_feature)
615+
{
616+
Some(rust_feature)
617+
} else {
618+
None
619+
}
620+
});
621+
let unknown_feature = if let Some(rust_feature) = rust_feature {
622+
UnknownCTargetFeature {
623+
feature,
624+
rust_feature: PossibleFeature::Some { rust_feature },
620625
}
621-
});
622-
let unknown_feature = if let Some(rust_feature) = rust_feature {
623-
UnknownCTargetFeature {
624-
feature,
625-
rust_feature: PossibleFeature::Some { rust_feature },
626-
}
627-
} else {
628-
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
629-
};
630-
sess.dcx().emit_warn(unknown_feature);
631-
} else if feature_state
632-
.is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
633-
{
634-
// An unstable feature. Warn about using it.
635-
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
626+
} else {
627+
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
628+
};
629+
sess.dcx().emit_warn(unknown_feature);
630+
} else if feature_state
631+
.is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
632+
{
633+
// An unstable feature. Warn about using it.
634+
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
635+
}
636636
}
637-
}
638637

639-
if diagnostics {
640-
// FIXME(nagisa): figure out how to not allocate a full hashset here.
641-
featsmap.insert(feature, enable_disable == '+');
642-
}
638+
if diagnostics {
639+
// FIXME(nagisa): figure out how to not allocate a full hashset here.
640+
featsmap.insert(feature, enable_disable == '+');
641+
}
643642

644-
// rustc-specific features do not get passed down to LLVM…
645-
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
646-
return None;
647-
}
643+
// rustc-specific features do not get passed down to LLVM…
644+
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
645+
return None;
646+
}
648647

649-
// if the target-feature is "backchain" and LLVM version is greater than 18
650-
// then we also need to add "+backchain" to the target-features attribute.
651-
// otherwise, we will only add the naked `backchain` attribute to the attribute-group.
652-
if feature == "backchain" && llvm_major < 18 {
653-
return None;
654-
}
655-
// ... otherwise though we run through `to_llvm_features` when
656-
// passing requests down to LLVM. This means that all in-language
657-
// features also work on the command line instead of having two
658-
// different names when the LLVM name and the Rust name differ.
659-
let llvm_feature = to_llvm_features(sess, feature);
660-
661-
Some(
662-
std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
663-
.chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
664-
match (enable_disable, feat) {
648+
// if the target-feature is "backchain" and LLVM version is greater than 18
649+
// then we also need to add "+backchain" to the target-features attribute.
650+
// otherwise, we will only add the naked `backchain` attribute to the attribute-group.
651+
if feature == "backchain" && llvm_major < 18 {
652+
return None;
653+
}
654+
// ... otherwise though we run through `to_llvm_features` when
655+
// passing requests down to LLVM. This means that all in-language
656+
// features also work on the command line instead of having two
657+
// different names when the LLVM name and the Rust name differ.
658+
let llvm_feature = to_llvm_features(sess, feature);
659+
660+
Some(
661+
std::iter::once(format!(
662+
"{}{}",
663+
enable_disable, llvm_feature.llvm_feature_name
664+
))
665+
.chain(llvm_feature.dependency.into_iter().filter_map(
666+
move |feat| match (enable_disable, feat) {
665667
('-' | '+', TargetFeatureFoldStrength::Both(f))
666668
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
667669
Some(format!("{enable_disable}{f}"))
668670
}
669671
_ => None,
670-
}
671-
})),
672-
)
673-
})
674-
.flatten();
675-
features.extend(feats);
672+
},
673+
)),
674+
)
675+
})
676+
.flatten();
677+
features.extend(feats);
678+
679+
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
680+
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
681+
features: f,
682+
span: None,
683+
missing_features: None,
684+
});
685+
}
686+
}
676687

677688
// -Zfixed-x18
678689
if sess.opts.unstable_opts.fixed_x18 {
@@ -683,14 +694,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
683694
}
684695
}
685696

686-
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
687-
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
688-
features: f,
689-
span: None,
690-
missing_features: None,
691-
});
692-
}
693-
694697
features
695698
}
696699

compiler/rustc_target/src/target_features.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,13 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
164164
// FEAT_SSBS & FEAT_SSBS2
165165
("ssbs", Stable, &[]),
166166
// FEAT_SVE
167-
("sve", Stable, &[]),
167+
// It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
168+
//
169+
// LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
170+
// exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
171+
//
172+
// "For backwards compatibility, Neon and VFP are required in the latest architectures."
173+
("sve", Stable, &["neon"]),
168174
// FEAT_SVE2
169175
("sve2", Stable, &["sve"]),
170176
// FEAT_SVE2_AES

tests/codegen/target-feature-overrides.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@ revisions: COMPAT INCOMPAT
22
//@ needs-llvm-components: x86
33
//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
4-
//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx,+sse4.2,+sse4.1,+ssse3,+sse3
4+
//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx
55
//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
66

77
// See also tests/assembly/target-feature-multiple.rs

0 commit comments

Comments
 (0)