1
1
use itertools:: Itertools ;
2
2
use std:: process:: Command ;
3
3
4
- use super :: argument:: Argument ;
5
4
use super :: indentation:: Indentation ;
6
5
use super :: intrinsic:: { IntrinsicDefinition , format_f16_return_value} ;
7
6
use super :: intrinsic_helpers:: IntrinsicTypeDefinition ;
@@ -188,66 +187,87 @@ pub fn generate_rust_test_loop<T: IntrinsicTypeDefinition>(
188
187
w : & mut impl std:: io:: Write ,
189
188
intrinsic : & dyn IntrinsicDefinition < T > ,
190
189
indentation : Indentation ,
191
- additional : & str ,
190
+ specializations : & [ Vec < u8 > ] ,
192
191
passes : u32 ,
193
192
) -> std:: io:: Result < ( ) > {
194
- let constraints = intrinsic. arguments ( ) . as_constraint_parameters_rust ( ) ;
195
- let constraints = if !constraints. is_empty ( ) {
196
- format ! ( "::<{constraints}>" )
197
- } else {
198
- constraints
199
- } ;
193
+ let intrinsic_name = intrinsic. name ( ) ;
194
+
195
+ // Each function (and each specialization) has its own type. Erase that type with a cast.
196
+ let mut coerce = String :: from ( "unsafe fn(" ) ;
197
+ for _ in intrinsic. arguments ( ) . iter ( ) . filter ( |a| !a. has_constraint ( ) ) {
198
+ coerce += "_, " ;
199
+ }
200
+ coerce += ") -> _" ;
201
+
202
+ match specializations {
203
+ [ ] => {
204
+ writeln ! ( w, " let specializations = [(\" \" , {intrinsic_name})];" ) ?;
205
+ }
206
+ [ const_args] if const_args. is_empty ( ) => {
207
+ writeln ! ( w, " let specializations = [(\" \" , {intrinsic_name})];" ) ?;
208
+ }
209
+ _ => {
210
+ writeln ! ( w, " let specializations = [" ) ?;
211
+
212
+ for specialization in specializations {
213
+ let mut specialization: Vec < _ > =
214
+ specialization. iter ( ) . map ( |d| d. to_string ( ) ) . collect ( ) ;
215
+
216
+ let const_args = specialization. join ( "," ) ;
217
+
218
+ // The identifier is reversed.
219
+ specialization. reverse ( ) ;
220
+ let id = specialization. join ( "-" ) ;
221
+
222
+ writeln ! (
223
+ w,
224
+ " (\" -{id}\" , {intrinsic_name}::<{const_args}> as {coerce}),"
225
+ ) ?;
226
+ }
227
+
228
+ writeln ! ( w, " ];" ) ?;
229
+ }
230
+ }
200
231
201
232
let return_value = format_f16_return_value ( intrinsic) ;
202
233
let indentation2 = indentation. nested ( ) ;
203
234
let indentation3 = indentation2. nested ( ) ;
204
235
writeln ! (
205
236
w,
206
- "{indentation}for i in 0..{passes} {{\n \
207
- {indentation2}unsafe {{\n \
208
- {loaded_args}\
209
- {indentation3}let __return_value = {intrinsic_call}{const}({args});\n \
210
- {indentation3}println!(\" Result {additional}-{{}}: {{:?}}\" , i + 1, {return_value});\n \
211
- {indentation2}}}\n \
212
- {indentation}}}",
237
+ "\
238
+ for (id, f) in specializations {{\n \
239
+ for i in 0..{passes} {{\n \
240
+ unsafe {{\n \
241
+ {loaded_args}\
242
+ let __return_value = f({args});\n \
243
+ println!(\" Result {{id}}-{{}}: {{:?}}\" , i + 1, {return_value});\n \
244
+ }}\n \
245
+ }}\n \
246
+ }}",
213
247
loaded_args = intrinsic. arguments( ) . load_values_rust( indentation3) ,
214
- intrinsic_call = intrinsic. name( ) ,
215
- const = constraints,
216
248
args = intrinsic. arguments( ) . as_call_param_rust( ) ,
217
249
)
218
250
}
219
251
220
- fn generate_rust_constraint_blocks < ' a , T : IntrinsicTypeDefinition + ' a > (
221
- w : & mut impl std:: io:: Write ,
222
- intrinsic : & dyn IntrinsicDefinition < T > ,
223
- indentation : Indentation ,
224
- constraints : & mut ( impl Iterator < Item = & ' a Argument < T > > + Clone ) ,
225
- name : String ,
226
- ) -> std:: io:: Result < ( ) > {
227
- let Some ( current) = constraints. next ( ) else {
228
- return generate_rust_test_loop ( w, intrinsic, indentation, & name, PASSES ) ;
229
- } ;
230
-
231
- let body_indentation = indentation. nested ( ) ;
232
- for i in current. constraint . iter ( ) . flat_map ( |c| c. to_range ( ) ) {
233
- let ty = current. ty . rust_type ( ) ;
234
-
235
- writeln ! ( w, "{indentation}{{" ) ?;
236
-
237
- writeln ! ( w, "{body_indentation}const {}: {ty} = {i};" , current. name) ?;
238
-
239
- generate_rust_constraint_blocks (
240
- w,
241
- intrinsic,
242
- body_indentation,
243
- & mut constraints. clone ( ) ,
244
- format ! ( "{name}-{i}" ) ,
245
- ) ?;
246
-
247
- writeln ! ( w, "{indentation}}}" ) ?;
252
+ /// Generate the specializations (unique sequences of const-generic arguments) for this intrinsic.
253
+ fn generate_rust_specializations < ' a > (
254
+ constraints : & mut impl Iterator < Item = std:: ops:: Range < i64 > > ,
255
+ ) -> Vec < Vec < u8 > > {
256
+ let mut specializations = vec ! [ vec![ ] ] ;
257
+
258
+ for constraint in constraints {
259
+ specializations = constraint
260
+ . flat_map ( |right| {
261
+ specializations. iter ( ) . map ( move |left| {
262
+ let mut left = left. clone ( ) ;
263
+ left. push ( u8:: try_from ( right) . unwrap ( ) ) ;
264
+ left
265
+ } )
266
+ } )
267
+ . collect ( ) ;
248
268
}
249
269
250
- Ok ( ( ) )
270
+ specializations
251
271
}
252
272
253
273
// Top-level function to create complete test program
@@ -265,13 +285,13 @@ pub fn create_rust_test_module<T: IntrinsicTypeDefinition>(
265
285
arguments. gen_arglists_rust ( w, indentation. nested ( ) , PASSES ) ?;
266
286
267
287
// Define any const generics as `const` items, then generate the actual test loop.
268
- generate_rust_constraint_blocks (
269
- w ,
270
- intrinsic ,
271
- indentation . nested ( ) ,
272
- & mut arguments . iter ( ) . rev ( ) . filter ( |i| i . has_constraint ( ) ) ,
273
- Default :: default ( ) ,
274
- ) ?;
288
+ let specializations = generate_rust_specializations (
289
+ & mut arguments
290
+ . iter ( )
291
+ . filter_map ( |i| i . constraint . as_ref ( ) . map ( |v| v . to_range ( ) ) ) ,
292
+ ) ;
293
+
294
+ generate_rust_test_loop ( w , intrinsic , indentation , & specializations , PASSES ) ?;
275
295
276
296
writeln ! ( w, "}}" ) ?;
277
297
0 commit comments