@@ -16,6 +16,7 @@ struct Function {
1616 doc : & ' static str ,
1717}
1818
19+ static BOOL : Type = Type :: PrimBool ;
1920static F16 : Type = Type :: PrimFloat ( 16 ) ;
2021static F32 : Type = Type :: PrimFloat ( 32 ) ;
2122static F64 : Type = Type :: PrimFloat ( 64 ) ;
@@ -28,6 +29,7 @@ static U32: Type = Type::PrimUnsigned(32);
2829static U64 : Type = Type :: PrimUnsigned ( 64 ) ;
2930static U8 : Type = Type :: PrimUnsigned ( 8 ) ;
3031static NEVER : Type = Type :: Never ;
32+ static VOID : Type = Type :: Void ;
3133static GENERICT : Type = Type :: GenericParam ( "T" ) ;
3234static GENERICU : Type = Type :: GenericParam ( "U" ) ;
3335
@@ -151,19 +153,70 @@ static U8X8X2: Type = Type::U(8, 8, 2);
151153static U8X8X3 : Type = Type :: U ( 8 , 8 , 3 ) ;
152154static U8X8X4 : Type = Type :: U ( 8 , 8 , 4 ) ;
153155
156+ static SVBOOL : Type = Type :: Pred ;
157+ static SVF32 : Type = Type :: SVF ( 32 , 1 ) ;
158+ static SVF32X2 : Type = Type :: SVF ( 32 , 2 ) ;
159+ static SVF32X3 : Type = Type :: SVF ( 32 , 3 ) ;
160+ static SVF32X4 : Type = Type :: SVF ( 32 , 4 ) ;
161+ static SVF64 : Type = Type :: SVF ( 64 , 1 ) ;
162+ static SVF64X2 : Type = Type :: SVF ( 64 , 2 ) ;
163+ static SVF64X3 : Type = Type :: SVF ( 64 , 3 ) ;
164+ static SVF64X4 : Type = Type :: SVF ( 64 , 4 ) ;
165+ static SVI8 : Type = Type :: SVI ( 8 , 1 ) ;
166+ static SVI8X2 : Type = Type :: SVI ( 8 , 2 ) ;
167+ static SVI8X3 : Type = Type :: SVI ( 8 , 3 ) ;
168+ static SVI8X4 : Type = Type :: SVI ( 8 , 4 ) ;
169+ static SVI16 : Type = Type :: SVI ( 16 , 1 ) ;
170+ static SVI16X2 : Type = Type :: SVI ( 16 , 2 ) ;
171+ static SVI16X3 : Type = Type :: SVI ( 16 , 3 ) ;
172+ static SVI16X4 : Type = Type :: SVI ( 16 , 4 ) ;
173+ static SVI32 : Type = Type :: SVI ( 32 , 1 ) ;
174+ static SVI32X2 : Type = Type :: SVI ( 32 , 2 ) ;
175+ static SVI32X3 : Type = Type :: SVI ( 32 , 3 ) ;
176+ static SVI32X4 : Type = Type :: SVI ( 32 , 4 ) ;
177+ static SVI64 : Type = Type :: SVI ( 64 , 1 ) ;
178+ static SVI64X2 : Type = Type :: SVI ( 64 , 2 ) ;
179+ static SVI64X3 : Type = Type :: SVI ( 64 , 3 ) ;
180+ static SVI64X4 : Type = Type :: SVI ( 64 , 4 ) ;
181+ static SVU8 : Type = Type :: SVU ( 8 , 1 ) ;
182+ static SVU8X2 : Type = Type :: SVU ( 8 , 2 ) ;
183+ static SVU8X3 : Type = Type :: SVU ( 8 , 3 ) ;
184+ static SVU8X4 : Type = Type :: SVU ( 8 , 4 ) ;
185+ static SVU16 : Type = Type :: SVU ( 16 , 1 ) ;
186+ static SVU16X2 : Type = Type :: SVU ( 16 , 2 ) ;
187+ static SVU16X3 : Type = Type :: SVU ( 16 , 3 ) ;
188+ static SVU16X4 : Type = Type :: SVU ( 16 , 4 ) ;
189+ static SVU32 : Type = Type :: SVU ( 32 , 1 ) ;
190+ static SVU32X2 : Type = Type :: SVU ( 32 , 2 ) ;
191+ static SVU32X3 : Type = Type :: SVU ( 32 , 3 ) ;
192+ static SVU32X4 : Type = Type :: SVU ( 32 , 4 ) ;
193+ static SVU64 : Type = Type :: SVU ( 64 , 1 ) ;
194+ static SVU64X2 : Type = Type :: SVU ( 64 , 2 ) ;
195+ static SVU64X3 : Type = Type :: SVU ( 64 , 3 ) ;
196+ static SVU64X4 : Type = Type :: SVU ( 64 , 4 ) ;
197+ static SVPRFOP : Type = Type :: Enum ( "svprfop" ) ;
198+ static SVPATTERN : Type = Type :: Enum ( "svpattern" ) ;
199+
154200#[ derive( Debug , Copy , Clone , PartialEq ) ]
155201enum Type {
202+ Void ,
203+ PrimBool ,
156204 PrimFloat ( u8 ) ,
157205 PrimSigned ( u8 ) ,
158206 PrimUnsigned ( u8 ) ,
159207 PrimPoly ( u8 ) ,
160208 MutPtr ( & ' static Type ) ,
161209 ConstPtr ( & ' static Type ) ,
210+ Enum ( & ' static str ) ,
162211 GenericParam ( & ' static str ) ,
163212 I ( u8 , u8 , u8 ) ,
164213 U ( u8 , u8 , u8 ) ,
165214 P ( u8 , u8 , u8 ) ,
166215 F ( u8 , u8 , u8 ) ,
216+ Pred ,
217+ SVI ( u8 , u8 ) ,
218+ SVU ( u8 , u8 ) ,
219+ SVF ( u8 , u8 ) ,
167220 Never ,
168221}
169222
@@ -182,19 +235,18 @@ fn verify_all_signatures() {
182235
183236 let mut all_valid = true ;
184237 for rust in FUNCTIONS {
238+ // Most SVE intrinsics just rely on the intrinsics test tool for validation
185239 if !rust. has_test {
186- if !SKIP_RUNTIME_TESTS . contains ( & rust. name ) {
187- println ! (
188- "missing run-time test named `test_{}` for `{}`" ,
189- {
190- let mut id = rust. name;
191- while id. starts_with( '_' ) {
192- id = & id[ 1 ..] ;
193- }
194- id
195- } ,
196- rust. name
197- ) ;
240+ if !SKIP_RUNTIME_TESTS . contains ( & rust. name )
241+ // Most run-time tests are handled by the intrinsic-test tool, except for
242+ // load/stores (which have generated tests)
243+ && ( !rust. name . starts_with ( "sv" ) || rust. name . starts_with ( "svld" )
244+ || rust. name . starts_with ( "svst" ) )
245+ // The load/store test generator can't handle these cases yet
246+ && ( !rust. name . contains ( "_u32base_" ) || rust. name . contains ( "index" ) || rust. name . contains ( "offset" ) )
247+ && !( rust. name . starts_with ( "svldff1" ) && rust. name . contains ( "gather" ) )
248+ {
249+ println ! ( "missing run-time test for `{}`" , rust. name) ;
198250 all_valid = false ;
199251 }
200252 }
@@ -269,12 +321,21 @@ fn matches(rust: &Function, arm: &Intrinsic) -> Result<(), String> {
269321 let mut nconst = 0 ;
270322 let iter = rust. arguments . iter ( ) . zip ( & arm. arguments ) . enumerate ( ) ;
271323 for ( i, ( rust_ty, ( arm, arm_const) ) ) in iter {
272- if * rust_ty != arm {
273- bail ! ( "mismatched arguments: {rust_ty:?} != {arm:?}" )
324+ match ( * rust_ty, arm) {
325+ // SVE uses generic type parameters to handle void pointers
326+ ( Type :: ConstPtr ( Type :: GenericParam ( "T" ) ) , Type :: ConstPtr ( Type :: Void ) ) => ( ) ,
327+ // SVE const generics use i32 over u64 for usability reasons
328+ ( Type :: PrimSigned ( 32 ) , Type :: PrimUnsigned ( 64 ) ) if rust. required_const . contains ( & i) => {
329+ ( )
330+ }
331+ // svset doesn't have its const argument last as we assumed when building the Function
332+ _ if rust. name . starts_with ( "svset" ) => ( ) ,
333+ ( x, y) if x == y => ( ) ,
334+ _ => bail ! ( "mismatched arguments: {rust_ty:?} != {arm:?}" ) ,
274335 }
275336 if * arm_const {
276337 nconst += 1 ;
277- if !rust. required_const . contains ( & i) {
338+ if !rust. required_const . contains ( & i) && !rust . name . starts_with ( "svset" ) {
278339 bail ! ( "argument const mismatch" ) ;
279340 }
280341 }
@@ -283,7 +344,7 @@ fn matches(rust: &Function, arm: &Intrinsic) -> Result<(), String> {
283344 bail ! ( "wrong number of const arguments" ) ;
284345 }
285346
286- if rust. instrs . is_empty ( ) {
347+ if rust. instrs . is_empty ( ) && arm . instruction != "" {
287348 bail ! (
288349 "instruction not listed for `{}`, but arm lists {:?}" ,
289350 rust. name,
@@ -322,7 +383,7 @@ fn matches(rust: &Function, arm: &Intrinsic) -> Result<(), String> {
322383 Ok ( ( ) )
323384}
324385
325- #[ derive( PartialEq ) ]
386+ #[ derive( Debug , PartialEq ) ]
326387struct Intrinsic {
327388 name : String ,
328389 ret : Option < Type > ,
@@ -337,7 +398,7 @@ struct JsonIntrinsic {
337398 arguments : Vec < String > ,
338399 return_type : ReturnType ,
339400 #[ serde( default ) ]
340- instructions : Vec < Vec < String > > ,
401+ instructions : Option < Vec < Vec < String > > > ,
341402}
342403
343404#[ derive( Deserialize , Debug ) ]
@@ -356,6 +417,8 @@ fn parse_intrinsics(intrinsics: Vec<JsonIntrinsic>) -> HashMap<String, Intrinsic
356417
357418fn parse_intrinsic ( mut intr : JsonIntrinsic ) -> Intrinsic {
358419 let name = intr. name ;
420+ // Remove '[' and ']' so that intrinsics of the form `svwhilerw[_s16]` becomes `svwhilerw_s16`.
421+ let name = name. replace ( '[' , "" ) . replace ( ']' , "" ) ;
359422 let ret = if intr. return_type . value == "void" {
360423 None
361424 } else {
@@ -364,18 +427,24 @@ fn parse_intrinsic(mut intr: JsonIntrinsic) -> Intrinsic {
364427
365428 // This ignores multiple instructions and different optional sequences for now to mimic
366429 // the old HTML scraping behaviour
367- let instruction = intr. instructions . swap_remove ( 0 ) . swap_remove ( 0 ) ;
430+ let instruction = intr
431+ . instructions
432+ . map_or ( String :: new ( ) , |mut i| i. swap_remove ( 0 ) . swap_remove ( 0 ) ) ;
368433
369434 let arguments = intr
370435 . arguments
371436 . iter ( )
372437 . map ( |s| {
373- let ( ty, konst) = match s. strip_prefix ( "const" ) {
374- Some ( stripped) => ( stripped. trim_start ( ) , true ) ,
375- None => ( s. as_str ( ) , false ) ,
438+ let ty = if let Some ( i) = s. find ( '*' ) {
439+ & s[ ..i + 1 ]
440+ } else {
441+ s. rsplit_once ( ' ' ) . unwrap ( ) . 0 . trim_start_matches ( "const " )
376442 } ;
377- let ty = ty. rsplit_once ( ' ' ) . unwrap ( ) . 0 ;
378- ( parse_ty ( ty) , konst)
443+ let ty = parse_ty ( ty) ;
444+ let konst = s. contains ( "const" ) && !matches ! ( ty, Type :: ConstPtr ( _) )
445+ || s. starts_with ( "enum" )
446+ || s. rsplit_once ( " " ) . unwrap ( ) . 1 . starts_with ( "imm" ) ;
447+ ( ty, konst)
379448 } )
380449 . collect :: < Vec < _ > > ( ) ;
381450
@@ -388,18 +457,27 @@ fn parse_intrinsic(mut intr: JsonIntrinsic) -> Intrinsic {
388457}
389458
390459fn parse_ty ( s : & str ) -> Type {
391- let suffix = " const *" ;
392- if let Some ( base) = s. strip_suffix ( suffix) {
393- Type :: ConstPtr ( parse_ty_base ( base) )
394- } else if let Some ( base) = s. strip_suffix ( " *" ) {
395- Type :: MutPtr ( parse_ty_base ( base) )
460+ if let Some ( ty) = s. strip_suffix ( "*" ) {
461+ let ty = ty. trim ( ) ;
462+ if let Some ( ty) = ty. strip_prefix ( "const" ) {
463+ // SVE intrinsics are west-const (`const int8_t *`)
464+ Type :: ConstPtr ( parse_ty_base ( ty) )
465+ } else if let Some ( ty) = ty. strip_suffix ( "const" ) {
466+ // Neon intrinsics are east-const (`int8_t const *`)
467+ Type :: ConstPtr ( parse_ty_base ( ty) )
468+ } else {
469+ Type :: MutPtr ( parse_ty_base ( ty) )
470+ }
396471 } else {
397472 * parse_ty_base ( s)
398473 }
399474}
400475
401476fn parse_ty_base ( s : & str ) -> & ' static Type {
477+ let s = s. trim ( ) ;
402478 match s {
479+ "bool" => & BOOL ,
480+ "void" => & VOID ,
403481 "float16_t" => & F16 ,
404482 "float16x4_t" => & F16X4 ,
405483 "float16x4x2_t" => & F16X4X2 ,
@@ -529,6 +607,49 @@ fn parse_ty_base(s: &str) -> &'static Type {
529607 "uint8x8x2_t" => & U8X8X2 ,
530608 "uint8x8x3_t" => & U8X8X3 ,
531609 "uint8x8x4_t" => & U8X8X4 ,
610+ "svbool_t" => & SVBOOL ,
611+ "svfloat32_t" => & SVF32 ,
612+ "svfloat32x2_t" => & SVF32X2 ,
613+ "svfloat32x3_t" => & SVF32X3 ,
614+ "svfloat32x4_t" => & SVF32X4 ,
615+ "svfloat64_t" => & SVF64 ,
616+ "svfloat64x2_t" => & SVF64X2 ,
617+ "svfloat64x3_t" => & SVF64X3 ,
618+ "svfloat64x4_t" => & SVF64X4 ,
619+ "svint8_t" => & SVI8 ,
620+ "svint8x2_t" => & SVI8X2 ,
621+ "svint8x3_t" => & SVI8X3 ,
622+ "svint8x4_t" => & SVI8X4 ,
623+ "svint16_t" => & SVI16 ,
624+ "svint16x2_t" => & SVI16X2 ,
625+ "svint16x3_t" => & SVI16X3 ,
626+ "svint16x4_t" => & SVI16X4 ,
627+ "svint32_t" => & SVI32 ,
628+ "svint32x2_t" => & SVI32X2 ,
629+ "svint32x3_t" => & SVI32X3 ,
630+ "svint32x4_t" => & SVI32X4 ,
631+ "svint64_t" => & SVI64 ,
632+ "svint64x2_t" => & SVI64X2 ,
633+ "svint64x3_t" => & SVI64X3 ,
634+ "svint64x4_t" => & SVI64X4 ,
635+ "svuint8_t" => & SVU8 ,
636+ "svuint8x2_t" => & SVU8X2 ,
637+ "svuint8x3_t" => & SVU8X3 ,
638+ "svuint8x4_t" => & SVU8X4 ,
639+ "svuint16_t" => & SVU16 ,
640+ "svuint16x2_t" => & SVU16X2 ,
641+ "svuint16x3_t" => & SVU16X3 ,
642+ "svuint16x4_t" => & SVU16X4 ,
643+ "svuint32_t" => & SVU32 ,
644+ "svuint32x2_t" => & SVU32X2 ,
645+ "svuint32x3_t" => & SVU32X3 ,
646+ "svuint32x4_t" => & SVU32X4 ,
647+ "svuint64_t" => & SVU64 ,
648+ "svuint64x2_t" => & SVU64X2 ,
649+ "svuint64x3_t" => & SVU64X3 ,
650+ "svuint64x4_t" => & SVU64X4 ,
651+ "enum svprfop" => & SVPRFOP ,
652+ "enum svpattern" => & SVPATTERN ,
532653
533654 _ => panic ! ( "failed to parse json type {s:?}" ) ,
534655 }
0 commit comments