@@ -17,6 +17,7 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy};
1717use rustc_target:: target_features:: { RUSTC_SPECIAL_FEATURES , RUSTC_SPECIFIC_FEATURES } ;
1818
1919use std:: ffi:: { c_char, c_void, CStr , CString } ;
20+ use std:: fmt;
2021use std:: fmt:: Write ;
2122use std:: path:: Path ;
2223use std:: ptr;
@@ -197,6 +198,12 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
197198 }
198199}
199200
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+
200207// WARNING: the features after applying `to_llvm_features` must be known
201208// to LLVM or the feature detection code will walk past the end of the feature
202209// array, leading to crashes.
@@ -209,7 +216,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
209216// Though note that Rust can also be build with an external precompiled version of LLVM
210217// which might lead to failures if the oldest tested / supported LLVM version
211218// 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 > > {
213220 let arch = if sess. target . arch == "x86_64" {
214221 "x86"
215222 } else if sess. target . arch == "arm64ec" {
@@ -218,77 +225,88 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
218225 & * sess. target . arch
219226 } ;
220227 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" ) ) ,
239247 // Rust ties fp and neon together.
240248 ( "aarch64" , "neon" ) => {
241- LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) )
249+ Some ( LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) ) )
242250 }
243251 // In LLVM neon implicitly enables fp, but we manually enable
244252 // 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+ ) ) ,
260273 ( "aarch64" , "sve" ) => {
261- LLVMFeature :: with_dependency ( "sve" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
274+ Some ( LLVMFeature :: with_dependency ( "sve" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ) )
262275 }
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 (
279297 "sve2-bitperm" ,
280298 TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
281- ) ,
299+ ) ) ,
282300 // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
283301 // `fast-unaligned-access`. In LLVM 19, it was split back out.
284302 ( "riscv32" | "riscv64" , "unaligned-scalar-mem" ) if get_version ( ) . 0 == 18 => {
285- LLVMFeature :: new ( "fast-unaligned-access" )
303+ Some ( LLVMFeature :: new ( "fast-unaligned-access" ) )
286304 }
287305 // For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled.
288306 ( "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" ) ) )
290308 }
291- ( _, s) => LLVMFeature :: new ( s) ,
309+ ( _, s) => Some ( LLVMFeature :: new ( s) ) ,
292310 }
293311}
294312
@@ -331,13 +349,17 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
331349 return true ;
332350 }
333351 // 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+ }
338358 }
359+ true
360+ } else {
361+ false
339362 }
340- true
341363 } )
342364 . map ( |feature| Symbol :: intern ( feature) )
343365 . collect ( )
@@ -388,13 +410,13 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> {
388410fn print_target_features ( out : & mut String , sess : & Session , tm : & llvm:: TargetMachine ) {
389411 let mut llvm_target_features = llvm_target_features ( tm) ;
390412 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
392414 . target
393415 . supported_target_features ( )
394416 . iter ( )
395- . map ( |( feature, _gate) | {
417+ . filter_map ( |( feature, _gate) | {
396418 // 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 ;
398420 let desc =
399421 match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
400422 Some ( index) => {
@@ -404,9 +426,9 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
404426 None => "" ,
405427 } ;
406428
407- ( * feature, desc)
429+ Some ( ( * feature, desc) )
408430 } )
409- . collect :: < Vec < _ > > ( ) ;
431+ . collect ( ) ;
410432
411433 // Since we add this at the end ...
412434 rustc_target_features. extend_from_slice ( & [ (
@@ -580,7 +602,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
580602 let feature_state = supported_features. iter ( ) . find ( |& & ( v, _) | v == feature) ;
581603 if feature_state. is_none ( ) {
582604 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) ? ;
584606 if llvm_features. contains ( feature) && !llvm_features. contains ( rust_feature)
585607 {
586608 Some ( rust_feature)
@@ -625,7 +647,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
625647 // passing requests down to LLVM. This means that all in-language
626648 // features also work on the command line instead of having two
627649 // 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) ? ;
629651
630652 Some (
631653 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> {
671693 let feature = s
672694 . strip_prefix ( & [ '+' , '-' ] [ ..] )
673695 . unwrap_or_else ( || sess. dcx ( ) . emit_fatal ( InvalidTargetFeaturePrefix { feature : s } ) ) ;
696+ if s. is_empty ( ) {
697+ return None ;
698+ }
674699 // Rustc-specific feature requests like `+crt-static` or `-crt-static`
675700 // are not passed down to LLVM.
676701 if RUSTC_SPECIFIC_FEATURES . contains ( & feature) {
0 commit comments