@@ -634,10 +634,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
634
634
let ( yes, yes_len) = this. operand_to_simd ( yes) ?;
635
635
let ( no, no_len) = this. operand_to_simd ( no) ?;
636
636
let ( dest, dest_len) = this. place_to_simd ( dest) ?;
637
+ let bitmask_len = dest_len. max ( 8 ) ;
637
638
638
639
assert ! ( mask. layout. ty. is_integral( ) ) ;
639
- assert_eq ! ( dest_len . max ( 8 ) , mask . layout . size . bits ( ) ) ;
640
- assert ! ( dest_len <= 64 ) ;
640
+ assert ! ( bitmask_len <= 64 ) ;
641
+ assert_eq ! ( bitmask_len , mask . layout . size . bits ( ) ) ;
641
642
assert_eq ! ( dest_len, yes_len) ;
642
643
assert_eq ! ( dest_len, no_len) ;
643
644
@@ -649,14 +650,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
649
650
. unwrap ( ) ;
650
651
for i in 0 ..dest_len {
651
652
let mask =
652
- mask & ( 1 << simd_bitmask_index ( i, dest_len , this. data_layout ( ) . endian ) ) ;
653
+ mask & ( 1 << simd_bitmask_index ( i, bitmask_len , this. data_layout ( ) . endian ) ) ;
653
654
let yes = this. read_immediate ( & this. mplace_index ( & yes, i) ?. into ( ) ) ?;
654
655
let no = this. read_immediate ( & this. mplace_index ( & no, i) ?. into ( ) ) ?;
655
656
let dest = this. mplace_index ( & dest, i) ?;
656
657
657
658
let val = if mask != 0 { yes } else { no } ;
658
659
this. write_immediate ( * val, & dest. into ( ) ) ?;
659
660
}
661
+ for i in dest_len..bitmask_len {
662
+ // If the mask is "padded", ensure that padding is all-zero.
663
+ let mask =
664
+ mask & ( 1 << simd_bitmask_index ( i, bitmask_len, this. data_layout ( ) . endian ) ) ;
665
+ if mask != 0 {
666
+ throw_ub_format ! (
667
+ "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits"
668
+ ) ;
669
+ }
670
+ }
660
671
}
661
672
#[ rustfmt:: skip]
662
673
"simd_cast" | "simd_as" => {
@@ -785,16 +796,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
785
796
"simd_bitmask" => {
786
797
let & [ ref op] = check_arg_count ( args) ?;
787
798
let ( op, op_len) = this. operand_to_simd ( op) ?;
799
+ let bitmask_len = op_len. max ( 8 ) ;
788
800
789
801
assert ! ( dest. layout. ty. is_integral( ) ) ;
790
- assert_eq ! ( op_len . max ( 8 ) , dest . layout . size . bits ( ) ) ;
791
- assert ! ( op_len <= 64 ) ;
802
+ assert ! ( bitmask_len <= 64 ) ;
803
+ assert_eq ! ( bitmask_len , dest . layout . size . bits ( ) ) ;
792
804
793
805
let mut res = 0u64 ;
794
806
for i in 0 ..op_len {
795
807
let op = this. read_immediate ( & this. mplace_index ( & op, i) ?. into ( ) ) ?;
796
808
if simd_element_to_bool ( op) ? {
797
- res |= 1 << simd_bitmask_index ( i, op_len , this. data_layout ( ) . endian ) ;
809
+ res |= 1 << simd_bitmask_index ( i, bitmask_len , this. data_layout ( ) . endian ) ;
798
810
}
799
811
}
800
812
this. write_int ( res, dest) ?;
@@ -1335,10 +1347,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool
1335
1347
} )
1336
1348
}
1337
1349
1338
- fn simd_bitmask_index ( idx : u64 , len : u64 , endianess : Endian ) -> u64 {
1339
- assert ! ( idx < len ) ;
1350
+ fn simd_bitmask_index ( idx : u64 , bitmask_len : u64 , endianess : Endian ) -> u64 {
1351
+ assert ! ( idx < bitmask_len ) ;
1340
1352
match endianess {
1341
1353
Endian :: Little => idx,
1342
- Endian :: Big => len . max ( 8 ) - 1 - idx, // reverse order of bits
1354
+ Endian :: Big => bitmask_len - 1 - idx, // reverse order of bits
1343
1355
}
1344
1356
}
0 commit comments