@@ -209,7 +209,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
209
209
// Though note that Rust can also be build with an external precompiled version of LLVM
210
210
// which might lead to failures if the oldest tested / supported LLVM version
211
211
// 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 > > {
213
213
let arch = if sess. target . arch == "x86_64" {
214
214
"x86"
215
215
} else if sess. target . arch == "arm64ec" {
@@ -218,40 +218,59 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a
218
218
& * sess. target . arch
219
219
} ;
220
220
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" ) ) ,
237
240
// Rust ties fp and neon together.
238
241
( "aarch64" , "neon" ) => {
239
- LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) )
242
+ Some ( LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) ) )
240
243
}
241
244
// In LLVM neon implicitly enables fp, but we manually enable
242
245
// 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 ,
245
264
// In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
246
265
// `fast-unaligned-access`. In LLVM 19, it was split back out.
247
266
( "riscv32" | "riscv64" , "unaligned-scalar-mem" ) if get_version ( ) . 0 == 18 => {
248
- LLVMFeature :: new ( "fast-unaligned-access" )
267
+ Some ( LLVMFeature :: new ( "fast-unaligned-access" ) )
249
268
}
250
269
// For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled.
251
270
( "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" ) ) )
253
272
}
254
- ( _, s) => LLVMFeature :: new ( s) ,
273
+ ( _, s) => Some ( LLVMFeature :: new ( s) ) ,
255
274
}
256
275
}
257
276
@@ -291,13 +310,17 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
291
310
return true ;
292
311
}
293
312
// 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
+ }
298
319
}
320
+ true
321
+ } else {
322
+ false
299
323
}
300
- true
301
324
} )
302
325
. map ( |( feature, _, _) | Symbol :: intern ( feature) ) ,
303
326
) ;
@@ -386,9 +409,9 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
386
409
. target
387
410
. supported_target_features ( )
388
411
. iter ( )
389
- . map ( |( feature, _gate, _implied) | {
412
+ . filter_map ( |( feature, _gate, _implied) | {
390
413
// 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 ;
392
415
let desc =
393
416
match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
394
417
Some ( index) => {
@@ -398,7 +421,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
398
421
None => "" ,
399
422
} ;
400
423
401
- ( * feature, desc)
424
+ Some ( ( * feature, desc) )
402
425
} )
403
426
. collect :: < Vec < _ > > ( ) ;
404
427
@@ -595,7 +618,7 @@ pub(crate) fn global_llvm_features(
595
618
if feature_state. is_none ( ) {
596
619
let rust_feature =
597
620
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) ? ;
599
622
if llvm_features. contains ( feature)
600
623
&& !llvm_features. contains ( rust_feature)
601
624
{
@@ -641,7 +664,7 @@ pub(crate) fn global_llvm_features(
641
664
// passing requests down to LLVM. This means that all in-language
642
665
// features also work on the command line instead of having two
643
666
// 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) ? ;
645
668
646
669
Some (
647
670
std:: iter:: once ( format ! (
@@ -691,6 +714,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
691
714
let feature = s
692
715
. strip_prefix ( & [ '+' , '-' ] [ ..] )
693
716
. unwrap_or_else ( || sess. dcx ( ) . emit_fatal ( InvalidTargetFeaturePrefix { feature : s } ) ) ;
717
+ if s. is_empty ( ) {
718
+ return None ;
719
+ }
694
720
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
695
721
// are not passed down to LLVM.
696
722
if RUSTC_SPECIFIC_FEATURES . contains ( & feature) {
0 commit comments