1
1
//@compile-flags: -Zmiri-strict-provenance
2
- #![ feature( portable_simd, platform_intrinsics, adt_const_params, inline_const) ]
2
+ #![ feature( portable_simd, platform_intrinsics, adt_const_params, inline_const, core_intrinsics ) ]
3
3
#![ allow( incomplete_features, internal_features) ]
4
+ use std:: intrinsics:: simd as intrinsics;
5
+ use std:: ptr;
4
6
use std:: simd:: { prelude:: * , StdFloat } ;
5
7
6
8
fn simd_ops_f32 ( ) {
@@ -421,6 +423,40 @@ fn simd_gather_scatter() {
421
423
let idxs = Simd :: from_array ( [ 9 , 3 , 0 , 0 ] ) ;
422
424
Simd :: from_array ( [ -27 , 82 , -41 , 124 ] ) . scatter ( & mut vec, idxs) ;
423
425
assert_eq ! ( vec, vec![ 124 , 11 , 12 , 82 , 14 , 15 , 16 , 17 , 18 ] ) ;
426
+
427
+ // We call the intrinsics directly to experiment with dangling pointers and masks.
428
+ let val = 42u8 ;
429
+ let ptrs: Simd < * const u8 , 4 > =
430
+ Simd :: from_array ( [ ptr:: null ( ) , ptr:: addr_of!( val) , ptr:: addr_of!( val) , ptr:: addr_of!( val) ] ) ;
431
+ let default = u8x4:: splat ( 0 ) ;
432
+ let mask = i8x4:: from_array ( [ 0 , !0 , 0 , !0 ] ) ;
433
+ let vals = unsafe { intrinsics:: simd_gather ( default, ptrs, mask) } ;
434
+ assert_eq ! ( vals, u8x4:: from_array( [ 0 , 42 , 0 , 42 ] ) , ) ;
435
+
436
+ let mut val1 = 0u8 ;
437
+ let mut val2 = 0u8 ;
438
+ let ptrs: Simd < * mut u8 , 4 > = Simd :: from_array ( [
439
+ ptr:: null_mut ( ) ,
440
+ ptr:: addr_of_mut!( val1) ,
441
+ ptr:: addr_of_mut!( val1) ,
442
+ ptr:: addr_of_mut!( val2) ,
443
+ ] ) ;
444
+ let vals = u8x4:: from_array ( [ 1 , 2 , 3 , 4 ] ) ;
445
+ unsafe { intrinsics:: simd_scatter ( vals, ptrs, mask) } ;
446
+ assert_eq ! ( val1, 2 ) ;
447
+ assert_eq ! ( val2, 4 ) ;
448
+
449
+ // Also check what happens when `scatter` has multiple overlapping pointers.
450
+ let mut val = 0u8 ;
451
+ let ptrs: Simd < * mut u8 , 4 > = Simd :: from_array ( [
452
+ ptr:: addr_of_mut!( val) ,
453
+ ptr:: addr_of_mut!( val) ,
454
+ ptr:: addr_of_mut!( val) ,
455
+ ptr:: addr_of_mut!( val) ,
456
+ ] ) ;
457
+ let vals = u8x4:: from_array ( [ 1 , 2 , 3 , 4 ] ) ;
458
+ unsafe { intrinsics:: simd_scatter ( vals, ptrs, mask) } ;
459
+ assert_eq ! ( val, 4 ) ;
424
460
}
425
461
426
462
fn simd_round ( ) {
@@ -460,14 +496,11 @@ fn simd_round() {
460
496
}
461
497
462
498
fn simd_intrinsics ( ) {
499
+ use intrinsics:: * ;
463
500
extern "platform-intrinsic" {
464
- fn simd_eq < T , U > ( x : T , y : T ) -> U ;
465
- fn simd_reduce_any < T > ( x : T ) -> bool ;
466
- fn simd_reduce_all < T > ( x : T ) -> bool ;
467
- fn simd_select < M , T > ( m : M , yes : T , no : T ) -> T ;
468
501
fn simd_shuffle_generic < T , U , const IDX : & ' static [ u32 ] > ( x : T , y : T ) -> U ;
469
- fn simd_shuffle < T , IDX , U > ( x : T , y : T , idx : IDX ) -> U ;
470
502
}
503
+
471
504
unsafe {
472
505
// Make sure simd_eq returns all-1 for `true`
473
506
let a = i32x4:: splat ( 10 ) ;
@@ -503,6 +536,29 @@ fn simd_intrinsics() {
503
536
}
504
537
}
505
538
539
+ fn simd_masked_loadstore ( ) {
540
+ // The buffer is deliberarely too short, so reading the last element would be UB.
541
+ let buf = [ 3i32 ; 3 ] ;
542
+ let default = i32x4:: splat ( 0 ) ;
543
+ let mask = i32x4:: from_array ( [ !0 , !0 , !0 , 0 ] ) ;
544
+ let vals = unsafe { intrinsics:: simd_masked_load ( mask, buf. as_ptr ( ) , default) } ;
545
+ assert_eq ! ( vals, i32x4:: from_array( [ 3 , 3 , 3 , 0 ] ) ) ;
546
+ // Also read in a way that the *first* element is OOB.
547
+ let mask2 = i32x4:: from_array ( [ 0 , !0 , !0 , !0 ] ) ;
548
+ let vals =
549
+ unsafe { intrinsics:: simd_masked_load ( mask2, buf. as_ptr ( ) . wrapping_sub ( 1 ) , default) } ;
550
+ assert_eq ! ( vals, i32x4:: from_array( [ 0 , 3 , 3 , 3 ] ) ) ;
551
+
552
+ // The buffer is deliberarely too short, so writing the last element would be UB.
553
+ let mut buf = [ 42i32 ; 3 ] ;
554
+ let vals = i32x4:: from_array ( [ 1 , 2 , 3 , 4 ] ) ;
555
+ unsafe { intrinsics:: simd_masked_store ( mask, buf. as_mut_ptr ( ) , vals) } ;
556
+ assert_eq ! ( buf, [ 1 , 2 , 3 ] ) ;
557
+ // Also write in a way that the *first* element is OOB.
558
+ unsafe { intrinsics:: simd_masked_store ( mask2, buf. as_mut_ptr ( ) . wrapping_sub ( 1 ) , vals) } ;
559
+ assert_eq ! ( buf, [ 2 , 3 , 4 ] ) ;
560
+ }
561
+
506
562
fn main ( ) {
507
563
simd_mask ( ) ;
508
564
simd_ops_f32 ( ) ;
@@ -513,4 +569,5 @@ fn main() {
513
569
simd_gather_scatter ( ) ;
514
570
simd_round ( ) ;
515
571
simd_intrinsics ( ) ;
572
+ simd_masked_loadstore ( ) ;
516
573
}
0 commit comments