@@ -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,36 +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- 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 > {
151204 let arch = if sess. target . arch == "x86_64" { "x86" } else { & * sess. target . arch } ;
152205 match ( arch, s) {
153- ( "x86" , "sse4.2" ) => smallvec ! [ "sse4.2" , "crc32" ] ,
154- ( "x86" , "pclmulqdq" ) => smallvec ! [ "pclmul" ] ,
155- ( "x86" , "rdrand" ) => smallvec ! [ "rdrnd" ] ,
156- ( "x86" , "bmi1" ) => smallvec ! [ "bmi" ] ,
157- ( "x86" , "cmpxchg16b" ) => smallvec ! [ "cx16" ] ,
158- ( "aarch64" , "rcpc2" ) => smallvec ! [ "rcpc-immo" ] ,
159- ( "aarch64" , "dpb" ) => smallvec ! [ "ccpp" ] ,
160- ( "aarch64" , "dpb2" ) => smallvec ! [ "ccdp" ] ,
161- ( "aarch64" , "frintts" ) => smallvec ! [ "fptoint" ] ,
162- ( "aarch64" , "fcma" ) => smallvec ! [ "complxnum" ] ,
163- ( "aarch64" , "pmuv3" ) => smallvec ! [ "perfmon" ] ,
164- ( "aarch64" , "paca" ) => smallvec ! [ "pauth" ] ,
165- ( "aarch64" , "pacg" ) => smallvec ! [ "pauth" ] ,
166- // Rust ties fp and neon together. In LLVM neon implicitly enables fp,
167- // but we manually enable neon when a feature only implicitly enables fp
168- ( "aarch64" , "f32mm" ) => smallvec ! [ "f32mm" , "neon" ] ,
169- ( "aarch64" , "f64mm" ) => smallvec ! [ "f64mm" , "neon" ] ,
170- ( "aarch64" , "fhm" ) => smallvec ! [ "fp16fml" , "neon" ] ,
171- ( "aarch64" , "fp16" ) => smallvec ! [ "fullfp16" , "neon" ] ,
172- ( "aarch64" , "jsconv" ) => smallvec ! [ "jsconv" , "neon" ] ,
173- ( "aarch64" , "sve" ) => smallvec ! [ "sve" , "neon" ] ,
174- ( "aarch64" , "sve2" ) => smallvec ! [ "sve2" , "neon" ] ,
175- ( "aarch64" , "sve2-aes" ) => smallvec ! [ "sve2-aes" , "neon" ] ,
176- ( "aarch64" , "sve2-sm4" ) => smallvec ! [ "sve2-sm4" , "neon" ] ,
177- ( "aarch64" , "sve2-sha3" ) => smallvec ! [ "sve2-sha3" , "neon" ] ,
178- ( "aarch64" , "sve2-bitperm" ) => smallvec ! [ "sve2-bitperm" , "neon" ] ,
179- ( _, s) => smallvec ! [ s] ,
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" ) ,
221+ // Rust ties fp and neon together.
222+ ( "aarch64" , "neon" ) => {
223+ LLVMFeature :: with_dependency ( "neon" , TargetFeatureFoldStrength :: Both ( "fp-armv8" ) )
224+ }
225+ // In LLVM neon implicitly enables fp, but we manually enable
226+ // neon when a feature only implicitly enables fp
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) ,
180262 }
181263}
182264
@@ -274,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
274356 let mut rustc_target_features = supported_target_features ( sess)
275357 . iter ( )
276358 . map ( |( feature, _gate) | {
277- let desc = if let Some ( llvm_feature) = to_llvm_features ( sess, * feature) . first ( ) {
278- // 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 =
279362 match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
280363 Some ( index) => {
281364 known_llvm_target_features. insert ( llvm_feature) ;
282365 llvm_target_features[ index] . 1
283366 }
284367 None => "" ,
285- }
286- } else {
287- ""
288- } ;
368+ } ;
369+
289370 ( * feature, desc)
290371 } )
291372 . collect :: < Vec < _ > > ( ) ;
@@ -469,10 +550,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
469550 // passing requests down to LLVM. This means that all in-language
470551 // features also work on the command line instead of having two
471552 // different names when the LLVM name and the Rust name differ.
553+ let llvm_feature = to_llvm_features ( sess, feature) ;
554+
472555 Some (
473- to_llvm_features ( sess, feature)
474- . into_iter ( )
475- . map ( move |f| format ! ( "{}{}" , enable_disable, f) ) ,
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+ } ) ) ,
476566 )
477567 } )
478568 . flatten ( ) ;
0 commit comments