@@ -306,45 +306,44 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
306306/// Must express features in the way Rust understands them.
307307///
308308/// 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 > ) {
312310 // Add base features for the target.
313311 // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
314312 // The reason is that if LLVM considers a feature implied but we do not, we don't want that to
315313 // 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.
318316 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 ;
338336 }
339- true
340- } else {
341- false
342337 }
343- } )
344- . map ( |( feature, _, _) | Symbol :: intern ( feature) ) ,
345- ) ;
338+ true
339+ } else {
340+ false
341+ }
342+ } )
343+ . map ( |( feature, _, _) | Symbol :: intern ( feature) )
344+ . collect ( ) ;
346345
347- // Add enabled features
346+ // Add enabled and remove disabled features.
348347 for ( enabled, feature) in
349348 sess. opts . cg . target_feature . split ( ',' ) . filter_map ( |s| match s. chars ( ) . next ( ) {
350349 Some ( '+' ) => Some ( ( true , Symbol :: intern ( & s[ 1 ..] ) ) ) ,
@@ -360,7 +359,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
360359 #[ allow( rustc:: potential_query_instability) ]
361360 features. extend (
362361 sess. target
363- . implied_target_features ( std :: iter :: once ( feature. as_str ( ) ) )
362+ . implied_target_features ( feature. as_str ( ) )
364363 . iter ( )
365364 . map ( |s| Symbol :: intern ( s) ) ,
366365 ) ;
@@ -371,11 +370,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
371370 // `features.contains` below.
372371 #[ allow( rustc:: potential_query_instability) ]
373372 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 ( ) ) {
379374 // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
380375 // remove `f`. (This is the standard logical contraposition principle.)
381376 false
@@ -387,25 +382,31 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
387382 }
388383 }
389384
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)
409410}
410411
411412pub ( crate ) fn print_version ( ) {
@@ -682,7 +683,7 @@ pub(crate) fn global_llvm_features(
682683 for feature in sess. opts . cg . target_feature . split ( ',' ) {
683684 if let Some ( feature) = feature. strip_prefix ( '+' ) {
684685 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) )
686687 . to_sorted_stable_ord ( )
687688 . iter ( )
688689 . map ( |& & s| ( true , s) ) ,
0 commit comments