@@ -16,7 +16,6 @@ use rustc_session::config::PrintRequest;
16
16
use rustc_session:: Session ;
17
17
use rustc_span:: symbol:: Symbol ;
18
18
use rustc_target:: spec:: { MergeFunctions , PanicStrategy } ;
19
- use smallvec:: { smallvec, SmallVec } ;
20
19
use std:: ffi:: { CStr , CString } ;
21
20
22
21
use std:: path:: Path ;
@@ -132,6 +131,60 @@ pub fn time_trace_profiler_finish(file_name: &Path) {
132
131
}
133
132
}
134
133
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
+
135
188
// WARNING: the features after applying `to_llvm_features` must be known
136
189
// to LLVM or the feature detection code will walk past the end of the feature
137
190
// array, leading to crashes.
@@ -147,58 +200,65 @@ pub fn time_trace_profiler_finish(file_name: &Path) {
147
200
// Though note that Rust can also be build with an external precompiled version of LLVM
148
201
// which might lead to failures if the oldest tested / supported LLVM version
149
202
// 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 > {
154
204
let arch = if sess. target . arch == "x86_64" { "x86" } else { & * sess. target . arch } ;
155
205
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" ) ,
169
221
// 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
+ }
171
225
// In LLVM neon implicitly enables fp, but we manually enable
172
226
// 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) ,
202
262
}
203
263
}
204
264
@@ -296,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
296
356
let mut rustc_target_features = supported_target_features ( sess)
297
357
. iter ( )
298
358
. 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 =
301
362
match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
302
363
Some ( index) => {
303
364
known_llvm_target_features. insert ( llvm_feature) ;
304
365
llvm_target_features[ index] . 1
305
366
}
306
367
None => "" ,
307
- }
308
- } else {
309
- ""
310
- } ;
368
+ } ;
369
+
311
370
( * feature, desc)
312
371
} )
313
372
. collect :: < Vec < _ > > ( ) ;
@@ -491,17 +550,20 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
491
550
// passing requests down to LLVM. This means that all in-language
492
551
// features also work on the command line instead of having two
493
552
// 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
+ )
505
567
} )
506
568
. flatten ( ) ;
507
569
features. extend ( feats) ;
0 commit comments