@@ -306,44 +306,44 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
306
306
/// Must express features in the way Rust understands them.
307
307
///
308
308
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
309
- pub ( crate ) fn target_features_cfg ( sess : & Session , allow_unstable : bool ) -> Vec < Symbol > {
310
- let mut features: FxHashSet < Symbol > = Default :: default ( ) ;
311
-
309
+ pub ( crate ) fn target_features_cfg ( sess : & Session ) -> ( Vec < Symbol > , Vec < Symbol > ) {
312
310
// Add base features for the target.
313
311
// We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
314
312
// The reason is that if LLVM considers a feature implied but we do not, we don't want that to
315
313
// show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of
316
- // the target CPU, that is still expanded to target features (with all their implied features) by
317
- // LLVM.
314
+ // the target CPU, that is still expanded to target features (with all their implied features)
315
+ // by LLVM.
318
316
let target_machine = create_informational_target_machine ( sess, true ) ;
319
- // Compute which of the known target features are enabled in the 'base' target machine.
320
- // We only consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
321
- features. extend (
322
- sess. target
323
- . rust_target_features ( )
324
- . iter ( )
325
- . filter ( |( feature, _, _) | {
326
- // skip checking special features, as LLVM may not understand them
327
- if RUSTC_SPECIAL_FEATURES . contains ( feature) {
328
- return true ;
329
- }
330
- // check that all features in a given smallvec are enabled
331
- if let Some ( feat) = to_llvm_features ( sess, feature) {
332
- for llvm_feature in feat {
333
- let cstr = SmallCStr :: new ( llvm_feature) ;
334
- if !unsafe { llvm:: LLVMRustHasFeature ( & target_machine, cstr. as_ptr ( ) ) } {
335
- return false ;
336
- }
317
+ // Compute which of the known target features are enabled in the 'base' target machine. We only
318
+ // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
319
+ let mut features: FxHashSet < Symbol > = sess
320
+ . target
321
+ . rust_target_features ( )
322
+ . iter ( )
323
+ . filter ( |( feature, _, _) | {
324
+ // skip checking special features, as LLVM may not understand them
325
+ if RUSTC_SPECIAL_FEATURES . contains ( feature) {
326
+ return true ;
327
+ }
328
+ if let Some ( feat) = to_llvm_features ( sess, feature) {
329
+ for llvm_feature in feat {
330
+ let cstr = SmallCStr :: new ( llvm_feature) ;
331
+ // `LLVMRustHasFeature` is moderately expensive. On targets with many
332
+ // features (e.g. x86) these calls take a non-trivial fraction of runtime
333
+ // when compiling very small programs.
334
+ if !unsafe { llvm:: LLVMRustHasFeature ( & target_machine, cstr. as_ptr ( ) ) } {
335
+ return false ;
337
336
}
338
- true
339
- } else {
340
- false
341
337
}
342
- } )
343
- . map ( |( feature, _, _) | Symbol :: intern ( feature) ) ,
344
- ) ;
338
+ true
339
+ } else {
340
+ false
341
+ }
342
+ } )
343
+ . map ( |( feature, _, _) | Symbol :: intern ( feature) )
344
+ . collect ( ) ;
345
345
346
- // Add enabled features
346
+ // Add enabled and remove disabled features.
347
347
for ( enabled, feature) in
348
348
sess. opts . cg . target_feature . split ( ',' ) . filter_map ( |s| match s. chars ( ) . next ( ) {
349
349
Some ( '+' ) => Some ( ( true , Symbol :: intern ( & s[ 1 ..] ) ) ) ,
@@ -359,7 +359,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
359
359
#[ allow( rustc:: potential_query_instability) ]
360
360
features. extend (
361
361
sess. target
362
- . implied_target_features ( std :: iter :: once ( feature. as_str ( ) ) )
362
+ . implied_target_features ( feature. as_str ( ) )
363
363
. iter ( )
364
364
. map ( |s| Symbol :: intern ( s) ) ,
365
365
) ;
@@ -370,11 +370,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
370
370
// `features.contains` below.
371
371
#[ allow( rustc:: potential_query_instability) ]
372
372
features. retain ( |f| {
373
- if sess
374
- . target
375
- . implied_target_features ( std:: iter:: once ( f. as_str ( ) ) )
376
- . contains ( & feature. as_str ( ) )
377
- {
373
+ if sess. target . implied_target_features ( f. as_str ( ) ) . contains ( & feature. as_str ( ) ) {
378
374
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
379
375
// remove `f`. (This is the standard logical contraposition principle.)
380
376
false
@@ -386,25 +382,31 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
386
382
}
387
383
}
388
384
389
- // Filter enabled features based on feature gates
390
- sess. target
391
- . rust_target_features ( )
392
- . iter ( )
393
- . filter_map ( |( feature, gate, _) | {
394
- // The `allow_unstable` set is used by rustc internally to determined which target
395
- // features are truly available, so we want to return even perma-unstable "forbidden"
396
- // features.
397
- if allow_unstable
398
- || ( gate. in_cfg ( ) && ( sess. is_nightly_build ( ) || gate. requires_nightly ( ) . is_none ( ) ) )
399
- {
400
- Some ( * feature)
401
- } else {
402
- None
403
- }
404
- } )
405
- . filter ( |feature| features. contains ( & Symbol :: intern ( feature) ) )
406
- . map ( |feature| Symbol :: intern ( feature) )
407
- . collect ( )
385
+ // Filter enabled features based on feature gates.
386
+ let f = |allow_unstable| {
387
+ sess. target
388
+ . rust_target_features ( )
389
+ . iter ( )
390
+ . filter_map ( |( feature, gate, _) | {
391
+ // The `allow_unstable` set is used by rustc internally to determined which target
392
+ // features are truly available, so we want to return even perma-unstable
393
+ // "forbidden" features.
394
+ if allow_unstable
395
+ || ( gate. in_cfg ( )
396
+ && ( sess. is_nightly_build ( ) || gate. requires_nightly ( ) . is_none ( ) ) )
397
+ {
398
+ Some ( Symbol :: intern ( feature) )
399
+ } else {
400
+ None
401
+ }
402
+ } )
403
+ . filter ( |feature| features. contains ( & feature) )
404
+ . collect ( )
405
+ } ;
406
+
407
+ let target_features = f ( false ) ;
408
+ let unstable_target_features = f ( true ) ;
409
+ ( target_features, unstable_target_features)
408
410
}
409
411
410
412
pub ( crate ) fn print_version ( ) {
@@ -681,7 +683,7 @@ pub(crate) fn global_llvm_features(
681
683
for feature in sess. opts . cg . target_feature . split ( ',' ) {
682
684
if let Some ( feature) = feature. strip_prefix ( '+' ) {
683
685
all_rust_features. extend (
684
- UnordSet :: from ( sess. target . implied_target_features ( std :: iter :: once ( feature) ) )
686
+ UnordSet :: from ( sess. target . implied_target_features ( feature) )
685
687
. to_sorted_stable_ord ( )
686
688
. iter ( )
687
689
. map ( |& & s| ( true , s) ) ,
0 commit comments