@@ -209,7 +209,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
209209// Though note that Rust can also be build with an external precompiled version of LLVM
210210// which might lead to failures if the oldest tested / supported LLVM version
211211// doesn't yet support the relevant intrinsics
212- pub ( crate ) fn to_llvm_features < ' a > ( sess : & Session , s : & ' a str ) -> LLVMFeature < ' a > {
212+ pub ( crate ) fn to_llvm_features < ' a > ( sess : & Session , s : & ' a str ) -> Option < LLVMFeature < ' a > > {
213213 let arch = if sess. target . arch == "x86_64" {
214214 "x86"
215215 } else if sess. target . arch == "arm64ec" {
@@ -218,40 +218,59 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a
218218 & * sess. target . arch
219219 } ;
220220 match ( arch, s) {
221- ( "x86" , "sse4.2" ) => {
222- LLVMFeature :: with_dependency ( "sse4.2" , TargetFeatureFoldStrength :: EnableOnly ( "crc32" ) )
223- }
224- ( "x86" , "pclmulqdq" ) => LLVMFeature :: new ( "pclmul" ) ,
225- ( "x86" , "rdrand" ) => LLVMFeature :: new ( "rdrnd" ) ,
226- ( "x86" , "bmi1" ) => LLVMFeature :: new ( "bmi" ) ,
227- ( "x86" , "cmpxchg16b" ) => LLVMFeature :: new ( "cx16" ) ,
228- ( "x86" , "lahfsahf" ) => LLVMFeature :: new ( "sahf" ) ,
229- ( "aarch64" , "rcpc2" ) => LLVMFeature :: new ( "rcpc-immo" ) ,
230- ( "aarch64" , "dpb" ) => LLVMFeature :: new ( "ccpp" ) ,
231- ( "aarch64" , "dpb2" ) => LLVMFeature :: new ( "ccdp" ) ,
232- ( "aarch64" , "frintts" ) => LLVMFeature :: new ( "fptoint" ) ,
233- ( "aarch64" , "fcma" ) => LLVMFeature :: new ( "complxnum" ) ,
234- ( "aarch64" , "pmuv3" ) => LLVMFeature :: new ( "perfmon" ) ,
235- ( "aarch64" , "paca" ) => LLVMFeature :: new ( "pauth" ) ,
236- ( "aarch64" , "pacg" ) => LLVMFeature :: new ( "pauth" ) ,
221+ ( "x86" , "sse4.2" ) => Some ( LLVMFeature :: with_dependency (
222+ "sse4.2" ,
223+ TargetFeatureFoldStrength :: EnableOnly ( "crc32" ) ,
224+ ) ) ,
225+ ( "x86" , "pclmulqdq" ) => Some ( LLVMFeature :: new ( "pclmul" ) ) ,
226+ ( "x86" , "rdrand" ) => Some ( LLVMFeature :: new ( "rdrnd" ) ) ,
227+ ( "x86" , "bmi1" ) => Some ( LLVMFeature :: new ( "bmi" ) ) ,
228+ ( "x86" , "cmpxchg16b" ) => Some ( LLVMFeature :: new ( "cx16" ) ) ,
229+ ( "x86" , "lahfsahf" ) => Some ( LLVMFeature :: new ( "sahf" ) ) ,
230+ ( "aarch64" , "rcpc2" ) => Some ( LLVMFeature :: new ( "rcpc-immo" ) ) ,
231+ ( "aarch64" , "dpb" ) => Some ( LLVMFeature :: new ( "ccpp" ) ) ,
232+ ( "aarch64" , "dpb2" ) => Some ( LLVMFeature :: new ( "ccdp" ) ) ,
233+ ( "aarch64" , "frintts" ) => Some ( LLVMFeature :: new ( "fptoint" ) ) ,
234+ ( "aarch64" , "fcma" ) => Some ( LLVMFeature :: new ( "complxnum" ) ) ,
235+ ( "aarch64" , "pmuv3" ) => Some ( LLVMFeature :: new ( "perfmon" ) ) ,
236+ ( "aarch64" , "paca" ) => Some ( LLVMFeature :: new ( "pauth" ) ) ,
237+ ( "aarch64" , "pacg" ) => Some ( LLVMFeature :: new ( "pauth" ) ) ,
238+ ( "aarch64" , "sve-b16b16" ) => Some ( LLVMFeature :: new ( "b16b16" ) ) ,
239+ ( "aarch64" , "flagm2" ) => Some ( LLVMFeature :: new ( "altnzcv" ) ) ,
237240 // Rust ties fp and neon together.
238241 ( "aarch64" , "neon" ) => {
239- LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) )
242+ Some ( LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) ) )
240243 }
241244 // In LLVM neon implicitly enables fp, but we manually enable
242245 // neon when a feature only implicitly enables fp
243- ( "aarch64" , "fhm" ) => LLVMFeature :: new ( "fp16fml" ) ,
244- ( "aarch64" , "fp16" ) => LLVMFeature :: new ( "fullfp16" ) ,
246+ ( "aarch64" , "fhm" ) => Some ( LLVMFeature :: new ( "fp16fml" ) ) ,
247+ ( "aarch64" , "fp16" ) => Some ( LLVMFeature :: new ( "fullfp16" ) ) ,
248+ // Filter out features that are not supported by the current LLVM version
249+ ( "aarch64" , "faminmax" ) if get_version ( ) . 0 < 18 => None ,
250+ ( "aarch64" , "fp8" ) if get_version ( ) . 0 < 18 => None ,
251+ ( "aarch64" , "fp8dot2" ) if get_version ( ) . 0 < 18 => None ,
252+ ( "aarch64" , "fp8dot4" ) if get_version ( ) . 0 < 18 => None ,
253+ ( "aarch64" , "fp8fma" ) if get_version ( ) . 0 < 18 => None ,
254+ ( "aarch64" , "fpmr" ) if get_version ( ) . 0 != 18 => None ,
255+ ( "aarch64" , "lut" ) if get_version ( ) . 0 < 18 => None ,
256+ ( "aarch64" , "sme-f8f16" ) if get_version ( ) . 0 < 18 => None ,
257+ ( "aarch64" , "sme-f8f32" ) if get_version ( ) . 0 < 18 => None ,
258+ ( "aarch64" , "sme-fa64" ) if get_version ( ) . 0 < 18 => None ,
259+ ( "aarch64" , "sme-lutv2" ) if get_version ( ) . 0 < 18 => None ,
260+ ( "aarch64" , "ssve-fp8dot2" ) if get_version ( ) . 0 < 18 => None ,
261+ ( "aarch64" , "ssve-fp8dot4" ) if get_version ( ) . 0 < 18 => None ,
262+ ( "aarch64" , "ssve-fp8fma" ) if get_version ( ) . 0 < 18 => None ,
263+ ( "aarch64" , "v9.5a" ) if get_version ( ) . 0 < 18 => None ,
245264 // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
246265 // `fast-unaligned-access`. In LLVM 19, it was split back out.
247266 ( "riscv32" | "riscv64" , "unaligned-scalar-mem" ) if get_version ( ) . 0 == 18 => {
248- LLVMFeature :: new ( "fast-unaligned-access" )
267+ Some ( LLVMFeature :: new ( "fast-unaligned-access" ) )
249268 }
250269 // For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled.
251270 ( "x86" , s) if get_version ( ) . 0 >= 18 && s. starts_with ( "avx512" ) => {
252- LLVMFeature :: with_dependency ( s, TargetFeatureFoldStrength :: EnableOnly ( "evex512" ) )
271+ Some ( LLVMFeature :: with_dependency ( s, TargetFeatureFoldStrength :: EnableOnly ( "evex512" ) ) )
253272 }
254- ( _, s) => LLVMFeature :: new ( s) ,
273+ ( _, s) => Some ( LLVMFeature :: new ( s) ) ,
255274 }
256275}
257276
@@ -291,13 +310,17 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
291310 return true ;
292311 }
293312 // check that all features in a given smallvec are enabled
294- for llvm_feature in to_llvm_features ( sess, feature) {
295- let cstr = SmallCStr :: new ( llvm_feature) ;
296- if !unsafe { llvm:: LLVMRustHasFeature ( & target_machine, cstr. as_ptr ( ) ) } {
297- return false ;
313+ if let Some ( feat) = to_llvm_features ( sess, feature) {
314+ for llvm_feature in feat {
315+ let cstr = SmallCStr :: new ( llvm_feature) ;
316+ if !unsafe { llvm:: LLVMRustHasFeature ( & target_machine, cstr. as_ptr ( ) ) } {
317+ return false ;
318+ }
298319 }
320+ true
321+ } else {
322+ false
299323 }
300- true
301324 } )
302325 . map ( |( feature, _, _) | Symbol :: intern ( feature) ) ,
303326 ) ;
@@ -386,9 +409,9 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
386409 . target
387410 . supported_target_features ( )
388411 . iter ( )
389- . map ( |( feature, _gate, _implied) | {
412+ . filter_map ( |( feature, _gate, _implied) | {
390413 // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
391- let llvm_feature = to_llvm_features ( sess, * feature) . llvm_feature_name ;
414+ let llvm_feature = to_llvm_features ( sess, * feature) ? . llvm_feature_name ;
392415 let desc =
393416 match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
394417 Some ( index) => {
@@ -398,7 +421,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
398421 None => "" ,
399422 } ;
400423
401- ( * feature, desc)
424+ Some ( ( * feature, desc) )
402425 } )
403426 . collect :: < Vec < _ > > ( ) ;
404427
@@ -595,7 +618,7 @@ pub(crate) fn global_llvm_features(
595618 if feature_state. is_none ( ) {
596619 let rust_feature =
597620 supported_features. iter ( ) . find_map ( |& ( rust_feature, _, _) | {
598- let llvm_features = to_llvm_features ( sess, rust_feature) ;
621+ let llvm_features = to_llvm_features ( sess, rust_feature) ? ;
599622 if llvm_features. contains ( feature)
600623 && !llvm_features. contains ( rust_feature)
601624 {
@@ -641,7 +664,7 @@ pub(crate) fn global_llvm_features(
641664 // passing requests down to LLVM. This means that all in-language
642665 // features also work on the command line instead of having two
643666 // different names when the LLVM name and the Rust name differ.
644- let llvm_feature = to_llvm_features ( sess, feature) ;
667+ let llvm_feature = to_llvm_features ( sess, feature) ? ;
645668
646669 Some (
647670 std:: iter:: once ( format ! (
@@ -691,6 +714,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
691714 let feature = s
692715 . strip_prefix ( & [ '+' , '-' ] [ ..] )
693716 . unwrap_or_else ( || sess. dcx ( ) . emit_fatal ( InvalidTargetFeaturePrefix { feature : s } ) ) ;
717+ if s. is_empty ( ) {
718+ return None ;
719+ }
694720 // Rustc-specific feature requests like `+crt-static` or `-crt-static`
695721 // are not passed down to LLVM.
696722 if RUSTC_SPECIFIC_FEATURES . contains ( & feature) {
0 commit comments