@@ -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,36 +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
- 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 > {
151
204
let arch = if sess. target . arch == "x86_64" { "x86" } else { & * sess. target . arch } ;
152
205
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) ,
180
262
}
181
263
}
182
264
@@ -274,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
274
356
let mut rustc_target_features = supported_target_features ( sess)
275
357
. iter ( )
276
358
. 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 =
279
362
match llvm_target_features. binary_search_by_key ( & llvm_feature, |( f, _d) | f) . ok ( ) {
280
363
Some ( index) => {
281
364
known_llvm_target_features. insert ( llvm_feature) ;
282
365
llvm_target_features[ index] . 1
283
366
}
284
367
None => "" ,
285
- }
286
- } else {
287
- ""
288
- } ;
368
+ } ;
369
+
289
370
( * feature, desc)
290
371
} )
291
372
. collect :: < Vec < _ > > ( ) ;
@@ -469,10 +550,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
469
550
// passing requests down to LLVM. This means that all in-language
470
551
// features also work on the command line instead of having two
471
552
// different names when the LLVM name and the Rust name differ.
553
+ let llvm_feature = to_llvm_features ( sess, feature) ;
554
+
472
555
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
+ } ) ) ,
476
566
)
477
567
} )
478
568
. flatten ( ) ;
0 commit comments