@@ -306,45 +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 . raw ( ) , cstr . as_ptr ( ) ) }
335
- {
336
- return false ;
337
- }
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 . raw ( ) , cstr . as_ptr ( ) ) } {
335
+ return false ;
338
336
}
339
- true
340
- } else {
341
- false
342
337
}
343
- } )
344
- . map ( |( feature, _, _) | Symbol :: intern ( feature) ) ,
345
- ) ;
338
+ true
339
+ } else {
340
+ false
341
+ }
342
+ } )
343
+ . map ( |( feature, _, _) | Symbol :: intern ( feature) )
344
+ . collect ( ) ;
346
345
347
- // Add enabled features
346
+ // Add enabled and remove disabled features.
348
347
for ( enabled, feature) in
349
348
sess. opts . cg . target_feature . split ( ',' ) . filter_map ( |s| match s. chars ( ) . next ( ) {
350
349
Some ( '+' ) => Some ( ( true , Symbol :: intern ( & s[ 1 ..] ) ) ) ,
@@ -360,7 +359,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
360
359
#[ allow( rustc:: potential_query_instability) ]
361
360
features. extend (
362
361
sess. target
363
- . implied_target_features ( std :: iter :: once ( feature. as_str ( ) ) )
362
+ . implied_target_features ( feature. as_str ( ) )
364
363
. iter ( )
365
364
. map ( |s| Symbol :: intern ( s) ) ,
366
365
) ;
@@ -371,11 +370,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
371
370
// `features.contains` below.
372
371
#[ allow( rustc:: potential_query_instability) ]
373
372
features. retain ( |f| {
374
- if sess
375
- . target
376
- . implied_target_features ( std:: iter:: once ( f. as_str ( ) ) )
377
- . contains ( & feature. as_str ( ) )
378
- {
373
+ if sess. target . implied_target_features ( f. as_str ( ) ) . contains ( & feature. as_str ( ) ) {
379
374
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
380
375
// remove `f`. (This is the standard logical contraposition principle.)
381
376
false
@@ -387,25 +382,31 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
387
382
}
388
383
}
389
384
390
- // Filter enabled features based on feature gates
391
- sess. target
392
- . rust_target_features ( )
393
- . iter ( )
394
- . filter_map ( |( feature, gate, _) | {
395
- // The `allow_unstable` set is used by rustc internally to determined which target
396
- // features are truly available, so we want to return even perma-unstable "forbidden"
397
- // features.
398
- if allow_unstable
399
- || ( gate. in_cfg ( ) && ( sess. is_nightly_build ( ) || gate. requires_nightly ( ) . is_none ( ) ) )
400
- {
401
- Some ( * feature)
402
- } else {
403
- None
404
- }
405
- } )
406
- . filter ( |feature| features. contains ( & Symbol :: intern ( feature) ) )
407
- . map ( |feature| Symbol :: intern ( feature) )
408
- . 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)
409
410
}
410
411
411
412
pub ( crate ) fn print_version ( ) {
@@ -682,7 +683,7 @@ pub(crate) fn global_llvm_features(
682
683
for feature in sess. opts . cg . target_feature . split ( ',' ) {
683
684
if let Some ( feature) = feature. strip_prefix ( '+' ) {
684
685
all_rust_features. extend (
685
- UnordSet :: from ( sess. target . implied_target_features ( std :: iter :: once ( feature) ) )
686
+ UnordSet :: from ( sess. target . implied_target_features ( feature) )
686
687
. to_sorted_stable_ord ( )
687
688
. iter ( )
688
689
. map ( |& & s| ( true , s) ) ,
0 commit comments