@@ -16,7 +16,6 @@ use rustc_session::config::PrintRequest;
1616use rustc_session:: Session ;
1717use rustc_span:: symbol:: Symbol ;
1818use rustc_target:: spec:: { MergeFunctions , PanicStrategy } ;
19- use smallvec:: { smallvec, SmallVec } ;
2019use std:: ffi:: { CStr , CString } ;
2120
2221use std:: path:: Path ;
@@ -132,6 +131,60 @@ pub fn time_trace_profiler_finish(file_name: &Path) {
132131 }
133132}
134133
134+ pub enum TargetFeatureFoldStrength < ' a > {
135+ // The feature is only tied when enabling the feature, disabling
136+ // this feature shouldn't disable the tied feature.
137+ EnableOnly ( & ' a str ) ,
138+ // The feature is tied for both enabling and disabling this feature.
139+ Both ( & ' a str ) ,
140+ }
141+
142+ impl < ' a > TargetFeatureFoldStrength < ' a > {
143+ fn as_str ( & self ) -> & ' a str {
144+ match self {
145+ TargetFeatureFoldStrength :: EnableOnly ( feat) => feat,
146+ TargetFeatureFoldStrength :: Both ( feat) => feat,
147+ }
148+ }
149+ }
150+
151+ pub struct LLVMFeature < ' a > {
152+ pub llvm_feature_name : & ' a str ,
153+ pub dependency : Option < TargetFeatureFoldStrength < ' a > > ,
154+ }
155+
156+ impl < ' a > LLVMFeature < ' a > {
157+ pub fn new ( llvm_feature_name : & ' a str ) -> Self {
158+ Self { llvm_feature_name, dependency : None }
159+ }
160+
161+ pub fn with_dependency (
162+ llvm_feature_name : & ' a str ,
163+ dependency : TargetFeatureFoldStrength < ' a > ,
164+ ) -> Self {
165+ Self { llvm_feature_name, dependency : Some ( dependency) }
166+ }
167+
168+ pub fn contains ( & self , feat : & str ) -> bool {
169+ self . iter ( ) . any ( |dep| dep == feat)
170+ }
171+
172+ pub fn iter ( & ' a self ) -> impl Iterator < Item = & ' a str > {
173+ let dependencies = self . dependency . iter ( ) . map ( |feat| feat. as_str ( ) ) ;
174+ std:: iter:: once ( self . llvm_feature_name ) . chain ( dependencies)
175+ }
176+ }
177+
178+ impl < ' a > IntoIterator for LLVMFeature < ' a > {
179+ type Item = & ' a str ;
180+ type IntoIter = impl Iterator < Item = & ' a str > ;
181+
182+ fn into_iter ( self ) -> Self :: IntoIter {
183+ let dependencies = self . dependency . into_iter ( ) . map ( |feat| feat. as_str ( ) ) ;
184+ std:: iter:: once ( self . llvm_feature_name ) . chain ( dependencies)
185+ }
186+ }
187+
135188// WARNING: the features after applying `to_llvm_features` must be known
136189// to LLVM or the feature detection code will walk past the end of the feature
137190// array, leading to crashes.
@@ -147,58 +200,65 @@ pub fn time_trace_profiler_finish(file_name: &Path) {
147200// Though note that Rust can also be build with an external precompiled version of LLVM
148201// which might lead to failures if the oldest tested / supported LLVM version
149202// doesn't yet support the relevant intrinsics
150- //
151- // Note: The first feature in the list that is returned is the mapping to the feature that is
152- // provided from the `s` parameter.
153- pub fn to_llvm_features < ' a > ( sess : & Session , s : & ' a str ) -> SmallVec < [ & ' a str ; 2 ] > {
203+ pub fn to_llvm_features < ' a > ( sess : & Session , s : & ' a str ) -> LLVMFeature < ' a > {
154204 let arch = if sess. target . arch == "x86_64" { "x86" } else { & * sess. target . arch } ;
155205 match ( arch, s) {
156- ( "x86" , "sse4.2" ) => smallvec ! [ "sse4.2" , "crc32" ] ,
157- ( "x86" , "pclmulqdq" ) => smallvec ! [ "pclmul" ] ,
158- ( "x86" , "rdrand" ) => smallvec ! [ "rdrnd" ] ,
159- ( "x86" , "bmi1" ) => smallvec ! [ "bmi" ] ,
160- ( "x86" , "cmpxchg16b" ) => smallvec ! [ "cx16" ] ,
161- ( "aarch64" , "rcpc2" ) => smallvec ! [ "rcpc-immo" ] ,
162- ( "aarch64" , "dpb" ) => smallvec ! [ "ccpp" ] ,
163- ( "aarch64" , "dpb2" ) => smallvec ! [ "ccdp" ] ,
164- ( "aarch64" , "frintts" ) => smallvec ! [ "fptoint" ] ,
165- ( "aarch64" , "fcma" ) => smallvec ! [ "complxnum" ] ,
166- ( "aarch64" , "pmuv3" ) => smallvec ! [ "perfmon" ] ,
167- ( "aarch64" , "paca" ) => smallvec ! [ "pauth" ] ,
168- ( "aarch64" , "pacg" ) => smallvec ! [ "pauth" ] ,
206+ ( "x86" , "sse4.2" ) => {
207+ LLVMFeature :: with_dependency ( "sse4.2" , TargetFeatureFoldStrength :: EnableOnly ( "crc32" ) )
208+ }
209+ ( "x86" , "pclmulqdq" ) => LLVMFeature :: new ( "pclmul" ) ,
210+ ( "x86" , "rdrand" ) => LLVMFeature :: new ( "rdrnd" ) ,
211+ ( "x86" , "bmi1" ) => LLVMFeature :: new ( "bmi" ) ,
212+ ( "x86" , "cmpxchg16b" ) => LLVMFeature :: new ( "cx16" ) ,
213+ ( "aarch64" , "rcpc2" ) => LLVMFeature :: new ( "rcpc-immo" ) ,
214+ ( "aarch64" , "dpb" ) => LLVMFeature :: new ( "ccpp" ) ,
215+ ( "aarch64" , "dpb2" ) => LLVMFeature :: new ( "ccdp" ) ,
216+ ( "aarch64" , "frintts" ) => LLVMFeature :: new ( "fptoint" ) ,
217+ ( "aarch64" , "fcma" ) => LLVMFeature :: new ( "complxnum" ) ,
218+ ( "aarch64" , "pmuv3" ) => LLVMFeature :: new ( "perfmon" ) ,
219+ ( "aarch64" , "paca" ) => LLVMFeature :: new ( "pauth" ) ,
220+ ( "aarch64" , "pacg" ) => LLVMFeature :: new ( "pauth" ) ,
169221 // Rust ties fp and neon together.
170- ( "aarch64" , "neon" ) => smallvec ! [ "neon" , "fp-armv8" ] ,
222+ ( "aarch64" , "neon" ) => {
223+ LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) )
224+ }
171225 // In LLVM neon implicitly enables fp, but we manually enable
172226 // neon when a feature only implicitly enables fp
173- ( "aarch64" , "f32mm" ) => smallvec ! [ "f32mm" , "neon" ] ,
174- ( "aarch64" , "f64mm" ) => smallvec ! [ "f64mm" , "neon" ] ,
175- ( "aarch64" , "fhm" ) => smallvec ! [ "fp16fml" , "neon" ] ,
176- ( "aarch64" , "fp16" ) => smallvec ! [ "fullfp16" , "neon" ] ,
177- ( "aarch64" , "jsconv" ) => smallvec ! [ "jsconv" , "neon" ] ,
178- ( "aarch64" , "sve" ) => smallvec ! [ "sve" , "neon" ] ,
179- ( "aarch64" , "sve2" ) => smallvec ! [ "sve2" , "neon" ] ,
180- ( "aarch64" , "sve2-aes" ) => smallvec ! [ "sve2-aes" , "neon" ] ,
181- ( "aarch64" , "sve2-sm4" ) => smallvec ! [ "sve2-sm4" , "neon" ] ,
182- ( "aarch64" , "sve2-sha3" ) => smallvec ! [ "sve2-sha3" , "neon" ] ,
183- ( "aarch64" , "sve2-bitperm" ) => smallvec ! [ "sve2-bitperm" , "neon" ] ,
184- ( _, s) => smallvec ! [ s] ,
185- }
186- }
187-
188- pub enum TargetFeatureFoldStrength {
189- // The feature is only tied when enabling the feature, disabling
190- // this feature shouldn't disable the tied feature.
191- EnableOnly ,
192- // The feature is tied for both enabling and disabling this feature.
193- Both ,
194- }
195-
196- // Determines how the features are folded together, some features are
197- // linked a lot more than some others.
198- pub fn feature_fold_strength < ' a > ( feats : & SmallVec < [ & ' a str ; 2 ] > ) -> TargetFeatureFoldStrength {
199- match ( feats. get ( 0 ) , feats. get ( 1 ) ) {
200- ( Some ( & "neon" ) , Some ( & "fp-armv8" ) ) => TargetFeatureFoldStrength :: Both ,
201- _ => TargetFeatureFoldStrength :: EnableOnly ,
227+ ( "aarch64" , "f32mm" ) => {
228+ LLVMFeature :: with_dependency ( "f32mm" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
229+ }
230+ ( "aarch64" , "f64mm" ) => {
231+ LLVMFeature :: with_dependency ( "f64mm" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
232+ }
233+ ( "aarch64" , "fhm" ) => {
234+ LLVMFeature :: with_dependency ( "fp16fml" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
235+ }
236+ ( "aarch64" , "fp16" ) => {
237+ LLVMFeature :: with_dependency ( "fullfp16" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
238+ }
239+ ( "aarch64" , "jsconv" ) => {
240+ LLVMFeature :: with_dependency ( "jsconv" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
241+ }
242+ ( "aarch64" , "sve" ) => {
243+ LLVMFeature :: with_dependency ( "sve" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
244+ }
245+ ( "aarch64" , "sve2" ) => {
246+ LLVMFeature :: with_dependency ( "sve2" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
247+ }
248+ ( "aarch64" , "sve2-aes" ) => {
249+ LLVMFeature :: with_dependency ( "sve2-aes" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
250+ }
251+ ( "aarch64" , "sve2-sm4" ) => {
252+ LLVMFeature :: with_dependency ( "sve2-sm4" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
253+ }
254+ ( "aarch64" , "sve2-sha3" ) => {
255+ LLVMFeature :: with_dependency ( "sve2-sha3" , TargetFeatureFoldStrength :: EnableOnly ( "neon" ) )
256+ }
257+ ( "aarch64" , "sve2-bitperm" ) => LLVMFeature :: with_dependency (
258+ "sve2-bitperm" ,
259+ TargetFeatureFoldStrength :: EnableOnly ( "neon" ) ,
260+ ) ,
261+ ( _, s) => LLVMFeature :: new ( s) ,
202262 }
203263}
204264
@@ -296,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
296356 let mut rustc_target_features = supported_target_features ( sess)
297357 . iter ( )
298358 . map ( |( feature, _gate) | {
299- let desc = if let Some ( llvm_feature) = to_llvm_features ( sess, * feature) . first ( ) {
300- // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
359+ // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
360+ let llvm_feature = to_llvm_features ( sess, * feature) . llvm_feature_name ;
361+ let desc =
301362 match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
302363 Some ( index) => {
303364 known_llvm_target_features. insert ( llvm_feature) ;
304365 llvm_target_features[ index] . 1
305366 }
306367 None => "" ,
307- }
308- } else {
309- ""
310- } ;
368+ } ;
369+
311370 ( * feature, desc)
312371 } )
313372 . collect :: < Vec < _ > > ( ) ;
@@ -491,17 +550,20 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
491550 // passing requests down to LLVM. This means that all in-language
492551 // features also work on the command line instead of having two
493552 // different names when the LLVM name and the Rust name differ.
494- let llvm_features = to_llvm_features ( sess, feature) ;
495- Some ( to_llvm_features ( sess, feature) . into_iter ( ) . enumerate ( ) . filter_map (
496- move |( idx, f) | match ( enable_disable, feature_fold_strength ( & llvm_features) ) {
497- ( '-' | '+' , TargetFeatureFoldStrength :: Both )
498- | ( '+' , TargetFeatureFoldStrength :: EnableOnly ) => {
499- Some ( format ! ( "{}{}" , enable_disable, f) )
500- }
501- _ if idx == 0 => Some ( format ! ( "{}{}" , enable_disable, f) ) ,
502- _ => None ,
503- } ,
504- ) )
553+ let llvm_feature = to_llvm_features ( sess, feature) ;
554+
555+ Some (
556+ std:: iter:: once ( format ! ( "{}{}" , enable_disable, llvm_feature. llvm_feature_name) )
557+ . chain ( llvm_feature. dependency . into_iter ( ) . filter_map ( move |feat| {
558+ match ( enable_disable, feat) {
559+ ( '-' | '+' , TargetFeatureFoldStrength :: Both ( f) )
560+ | ( '+' , TargetFeatureFoldStrength :: EnableOnly ( f) ) => {
561+ Some ( format ! ( "{}{}" , enable_disable, f) )
562+ }
563+ _ => None ,
564+ }
565+ } ) ) ,
566+ )
505567 } )
506568 . flatten ( ) ;
507569 features. extend ( feats) ;
0 commit comments