@@ -17,6 +17,7 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy};
17
17
use rustc_target:: target_features:: { RUSTC_SPECIAL_FEATURES , RUSTC_SPECIFIC_FEATURES } ;
18
18
19
19
use std:: ffi:: { c_char, c_void, CStr , CString } ;
20
+ use std:: fmt;
20
21
use std:: fmt:: Write ;
21
22
use std:: path:: Path ;
22
23
use std:: ptr;
@@ -197,6 +198,12 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
197
198
}
198
199
}
199
200
201
+ impl < ' a > fmt:: Display for LLVMFeature < ' a > {
202
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
203
+ write ! ( f, "{}" , self . llvm_feature_name)
204
+ }
205
+ }
206
+
200
207
// WARNING: the features after applying `to_llvm_features` must be known
201
208
// to LLVM or the feature detection code will walk past the end of the feature
202
209
// array, leading to crashes.
@@ -209,7 +216,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
209
216
// Though note that Rust can also be build with an external precompiled version of LLVM
210
217
// which might lead to failures if the oldest tested / supported LLVM version
211
218
// doesn't yet support the relevant intrinsics
212
- pub fn to_llvm_features < ' a > ( sess : & Session , s : & ' a str ) -> LLVMFeature < ' a > {
219
+ pub fn to_llvm_features < ' a > ( sess : & Session , s : & ' a str ) -> Option < LLVMFeature < ' a > > {
213
220
let arch = if sess. target . arch == "x86_64" {
214
221
"x86"
215
222
} else if sess. target . arch == "arm64ec" {
@@ -218,77 +225,88 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
218
225
& * sess. target . arch
219
226
} ;
220
227
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" ) ,
237
- ( "aarch64" , "sve-b16b16" ) => LLVMFeature :: new ( "b16b16" ) ,
238
- ( "aarch64" , "flagm2" ) => LLVMFeature :: new ( "altnzcv" ) ,
228
+ ( "x86" , "sse4.2" ) => Some ( LLVMFeature :: with_dependency (
229
+ "sse4.2" ,
230
+ TargetFeatureFoldStrength :: EnableOnly ( "crc32" ) ,
231
+ ) ) ,
232
+ ( "x86" , "pclmulqdq" ) => Some ( LLVMFeature :: new ( "pclmul" ) ) ,
233
+ ( "x86" , "rdrand" ) => Some ( LLVMFeature :: new ( "rdrnd" ) ) ,
234
+ ( "x86" , "bmi1" ) => Some ( LLVMFeature :: new ( "bmi" ) ) ,
235
+ ( "x86" , "cmpxchg16b" ) => Some ( LLVMFeature :: new ( "cx16" ) ) ,
236
+ ( "x86" , "lahfsahf" ) => Some ( LLVMFeature :: new ( "sahf" ) ) ,
237
+ ( "aarch64" , "rcpc2" ) => Some ( LLVMFeature :: new ( "rcpc-immo" ) ) ,
238
+ ( "aarch64" , "dpb" ) => Some ( LLVMFeature :: new ( "ccpp" ) ) ,
239
+ ( "aarch64" , "dpb2" ) => Some ( LLVMFeature :: new ( "ccdp" ) ) ,
240
+ ( "aarch64" , "frintts" ) => Some ( LLVMFeature :: new ( "fptoint" ) ) ,
241
+ ( "aarch64" , "fcma" ) => Some ( LLVMFeature :: new ( "complxnum" ) ) ,
242
+ ( "aarch64" , "pmuv3" ) => Some ( LLVMFeature :: new ( "perfmon" ) ) ,
243
+ ( "aarch64" , "paca" ) => Some ( LLVMFeature :: new ( "pauth" ) ) ,
244
+ ( "aarch64" , "pacg" ) => Some ( LLVMFeature :: new ( "pauth" ) ) ,
245
+ ( "aarch64" , "sve-b16b16" ) => Some ( LLVMFeature :: new ( "b16b16" ) ) ,
246
+ ( "aarch64" , "flagm2" ) => Some ( LLVMFeature :: new ( "altnzcv" ) ) ,
239
247
// Rust ties fp and neon together.
240
248
( "aarch64" , "neon" ) => {
241
- LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) )
249
+ Some ( LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) ) )
242
250
}
243
251
// In LLVM neon implicitly enables fp, but we manually enable
244
252
// neon when a feature only implicitly enables fp
245
- ( "aarch64" , "f32mm" ) => {
246
- LLVMFeature :: with_dependency ( "f32mm" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
247
- }
248
- ( "aarch64" , "f64mm" ) => {
249
- LLVMFeature :: with_dependency ( "f64mm" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
250
- }
251
- ( "aarch64" , "fhm" ) => {
252
- LLVMFeature :: with_dependency ( "fp16fml" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
253
- }
254
- ( "aarch64" , "fp16" ) => {
255
- LLVMFeature :: with_dependency ( "fullfp16" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
256
- }
257
- ( "aarch64" , "jsconv" ) => {
258
- LLVMFeature :: with_dependency ( "jsconv" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
259
- }
253
+ ( "aarch64" , "f32mm" ) => Some ( LLVMFeature :: with_dependency (
254
+ "f32mm" ,
255
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
256
+ ) ) ,
257
+ ( "aarch64" , "f64mm" ) => Some ( LLVMFeature :: with_dependency (
258
+ "f64mm" ,
259
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
260
+ ) ) ,
261
+ ( "aarch64" , "fhm" ) => Some ( LLVMFeature :: with_dependency (
262
+ "fp16fml" ,
263
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
264
+ ) ) ,
265
+ ( "aarch64" , "fp16" ) => Some ( LLVMFeature :: with_dependency (
266
+ "fullfp16" ,
267
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
268
+ ) ) ,
269
+ ( "aarch64" , "jsconv" ) => Some ( LLVMFeature :: with_dependency (
270
+ "jsconv" ,
271
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
272
+ ) ) ,
260
273
( "aarch64" , "sve" ) => {
261
- LLVMFeature :: with_dependency ( "sve" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
274
+ Some ( LLVMFeature :: with_dependency ( "sve" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ) )
262
275
}
263
- ( "aarch64" , "sve2" ) => {
264
- LLVMFeature :: with_dependency ( "sve2" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
265
- }
266
- ( "aarch64" , "sve2p1" ) => {
267
- LLVMFeature :: with_dependency ( "sve2p1" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
268
- }
269
- ( "aarch64" , "sve2-aes" ) => {
270
- LLVMFeature :: with_dependency ( "sve2-aes" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
271
- }
272
- ( "aarch64" , "sve2-sm4" ) => {
273
- LLVMFeature :: with_dependency ( "sve2-sm4" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
274
- }
275
- ( "aarch64" , "sve2-sha3" ) => {
276
- LLVMFeature :: with_dependency ( "sve2-sha3" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
277
- }
278
- ( "aarch64" , "sve2-bitperm" ) => LLVMFeature :: with_dependency (
276
+ ( "aarch64" , "sve2" ) => Some ( LLVMFeature :: with_dependency (
277
+ "sve2" ,
278
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
279
+ ) ) ,
280
+ ( "aarch64" , "sve2p1" ) => Some ( LLVMFeature :: with_dependency (
281
+ "sve2p1" ,
282
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
283
+ ) ) ,
284
+ ( "aarch64" , "sve2-aes" ) => Some ( LLVMFeature :: with_dependency (
285
+ "sve2-aes" ,
286
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
287
+ ) ) ,
288
+ ( "aarch64" , "sve2-sm4" ) => Some ( LLVMFeature :: with_dependency (
289
+ "sve2-sm4" ,
290
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
291
+ ) ) ,
292
+ ( "aarch64" , "sve2-sha3" ) => Some ( LLVMFeature :: with_dependency (
293
+ "sve2-sha3" ,
294
+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
295
+ ) ) ,
296
+ ( "aarch64" , "sve2-bitperm" ) => Some ( LLVMFeature :: with_dependency (
279
297
"sve2-bitperm" ,
280
298
TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
281
- ) ,
299
+ ) ) ,
282
300
// In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
283
301
// `fast-unaligned-access`. In LLVM 19, it was split back out.
284
302
( "riscv32" | "riscv64" , "unaligned-scalar-mem" ) if get_version ( ) . 0 == 18 => {
285
- LLVMFeature :: new ( "fast-unaligned-access" )
303
+ Some ( LLVMFeature :: new ( "fast-unaligned-access" ) )
286
304
}
287
305
// For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled.
288
306
( "x86" , s) if get_version ( ) . 0 >= 18 && s. starts_with ( "avx512" ) => {
289
- LLVMFeature :: with_dependency ( s, TargetFeatureFoldStrength :: EnableOnly ( "evex512" ) )
307
+ Some ( LLVMFeature :: with_dependency ( s, TargetFeatureFoldStrength :: EnableOnly ( "evex512" ) ) )
290
308
}
291
- ( _, s) => LLVMFeature :: new ( s) ,
309
+ ( _, s) => Some ( LLVMFeature :: new ( s) ) ,
292
310
}
293
311
}
294
312
@@ -331,13 +349,17 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
331
349
return true ;
332
350
}
333
351
// check that all features in a given smallvec are enabled
334
- for llvm_feature in to_llvm_features ( sess, feature) {
335
- let cstr = SmallCStr :: new ( llvm_feature) ;
336
- if !unsafe { llvm:: LLVMRustHasFeature ( & target_machine, cstr. as_ptr ( ) ) } {
337
- return false ;
352
+ if let Some ( llvm_features) = to_llvm_features ( sess, feature) {
353
+ for llvm_feature in llvm_features {
354
+ let cstr = SmallCStr :: new ( llvm_feature) ;
355
+ if !unsafe { llvm:: LLVMRustHasFeature ( & target_machine, cstr. as_ptr ( ) ) } {
356
+ return false ;
357
+ }
338
358
}
359
+ true
360
+ } else {
361
+ false
339
362
}
340
- true
341
363
} )
342
364
. map ( |feature| Symbol :: intern ( feature) )
343
365
. collect ( )
@@ -388,13 +410,13 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> {
388
410
fn print_target_features ( out : & mut String , sess : & Session , tm : & llvm:: TargetMachine ) {
389
411
let mut llvm_target_features = llvm_target_features ( tm) ;
390
412
let mut known_llvm_target_features = FxHashSet :: < & ' static str > :: default ( ) ;
391
- let mut rustc_target_features = sess
413
+ let mut rustc_target_features: Vec < ( & str , & str ) > = sess
392
414
. target
393
415
. supported_target_features ( )
394
416
. iter ( )
395
- . map ( |( feature, _gate) | {
417
+ . filter_map ( |( feature, _gate) | {
396
418
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
397
- let llvm_feature = to_llvm_features ( sess, * feature) . llvm_feature_name ;
419
+ let llvm_feature = to_llvm_features ( sess, * feature) ? . llvm_feature_name ;
398
420
let desc =
399
421
match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
400
422
Some ( index) => {
@@ -404,9 +426,9 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
404
426
None => "" ,
405
427
} ;
406
428
407
- ( * feature, desc)
429
+ Some ( ( * feature, desc) )
408
430
} )
409
- . collect :: < Vec < _ > > ( ) ;
431
+ . collect ( ) ;
410
432
411
433
// Since we add this at the end ...
412
434
rustc_target_features. extend_from_slice ( & [ (
@@ -580,7 +602,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
580
602
let feature_state = supported_features. iter ( ) . find ( |& & ( v, _) | v == feature) ;
581
603
if feature_state. is_none ( ) {
582
604
let rust_feature = supported_features. iter ( ) . find_map ( |& ( rust_feature, _) | {
583
- let llvm_features = to_llvm_features ( sess, rust_feature) ;
605
+ let llvm_features = to_llvm_features ( sess, rust_feature) ? ;
584
606
if llvm_features. contains ( feature) && !llvm_features. contains ( rust_feature)
585
607
{
586
608
Some ( rust_feature)
@@ -625,7 +647,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
625
647
// passing requests down to LLVM. This means that all in-language
626
648
// features also work on the command line instead of having two
627
649
// different names when the LLVM name and the Rust name differ.
628
- let llvm_feature = to_llvm_features ( sess, feature) ;
650
+ let llvm_feature = to_llvm_features ( sess, feature) ? ;
629
651
630
652
Some (
631
653
std:: iter:: once ( format ! ( "{}{}" , enable_disable, llvm_feature. llvm_feature_name) )
@@ -671,6 +693,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
671
693
let feature = s
672
694
. strip_prefix ( & [ '+' , '-' ] [ ..] )
673
695
. unwrap_or_else ( || sess. dcx ( ) . emit_fatal ( InvalidTargetFeaturePrefix { feature : s } ) ) ;
696
+ if s. is_empty ( ) {
697
+ return None ;
698
+ }
674
699
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
675
700
// are not passed down to LLVM.
676
701
if RUSTC_SPECIFIC_FEATURES . contains ( & feature) {
0 commit comments