@@ -669,10 +669,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
669
669
let ( yes, yes_len) = this. operand_to_simd ( yes) ?;
670
670
let ( no, no_len) = this. operand_to_simd ( no) ?;
671
671
let ( dest, dest_len) = this. place_to_simd ( dest) ?;
672
+ let bitmask_len = dest_len. max ( 8 ) ;
672
673
673
674
assert ! ( mask. layout. ty. is_integral( ) ) ;
674
- assert_eq ! ( dest_len . max ( 8 ) , mask . layout . size . bits ( ) ) ;
675
- assert ! ( dest_len <= 64 ) ;
675
+ assert ! ( bitmask_len <= 64 ) ;
676
+ assert_eq ! ( bitmask_len , mask . layout . size . bits ( ) ) ;
676
677
assert_eq ! ( dest_len, yes_len) ;
677
678
assert_eq ! ( dest_len, no_len) ;
678
679
@@ -684,14 +685,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
684
685
. unwrap ( ) ;
685
686
for i in 0 ..dest_len {
686
687
let mask =
687
- mask & ( 1 << simd_bitmask_index ( i, dest_len , this. data_layout ( ) . endian ) ) ;
688
+ mask & ( 1 << simd_bitmask_index ( i, bitmask_len , this. data_layout ( ) . endian ) ) ;
688
689
let yes = this. read_immediate ( & this. mplace_index ( & yes, i) ?. into ( ) ) ?;
689
690
let no = this. read_immediate ( & this. mplace_index ( & no, i) ?. into ( ) ) ?;
690
691
let dest = this. mplace_index ( & dest, i) ?;
691
692
692
693
let val = if mask != 0 { yes } else { no } ;
693
694
this. write_immediate ( * val, & dest. into ( ) ) ?;
694
695
}
696
+ for i in dest_len..bitmask_len {
697
+ // If the mask is "padded", ensure that padding is all-zero.
698
+ let mask =
699
+ mask & ( 1 << simd_bitmask_index ( i, bitmask_len, this. data_layout ( ) . endian ) ) ;
700
+ if mask != 0 {
701
+ throw_ub_format ! (
702
+ "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits"
703
+ ) ;
704
+ }
705
+ }
695
706
}
696
707
#[ rustfmt:: skip]
697
708
"simd_cast" | "simd_as" => {
@@ -820,16 +831,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
820
831
"simd_bitmask" => {
821
832
let & [ ref op] = check_arg_count ( args) ?;
822
833
let ( op, op_len) = this. operand_to_simd ( op) ?;
834
+ let bitmask_len = op_len. max ( 8 ) ;
823
835
824
836
assert ! ( dest. layout. ty. is_integral( ) ) ;
825
- assert_eq ! ( op_len . max ( 8 ) , dest . layout . size . bits ( ) ) ;
826
- assert ! ( op_len <= 64 ) ;
837
+ assert ! ( bitmask_len <= 64 ) ;
838
+ assert_eq ! ( bitmask_len , dest . layout . size . bits ( ) ) ;
827
839
828
840
let mut res = 0u64 ;
829
841
for i in 0 ..op_len {
830
842
let op = this. read_immediate ( & this. mplace_index ( & op, i) ?. into ( ) ) ?;
831
843
if simd_element_to_bool ( op) ? {
832
- res |= 1 << simd_bitmask_index ( i, op_len , this. data_layout ( ) . endian ) ;
844
+ res |= 1 << simd_bitmask_index ( i, bitmask_len , this. data_layout ( ) . endian ) ;
833
845
}
834
846
}
835
847
this. write_int ( res, dest) ?;
@@ -1370,10 +1382,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool
1370
1382
} )
1371
1383
}
1372
1384
1373
- fn simd_bitmask_index ( idx : u64 , len : u64 , endianess : Endian ) -> u64 {
1374
- assert ! ( idx < len ) ;
1385
+ fn simd_bitmask_index ( idx : u64 , bitmask_len : u64 , endianess : Endian ) -> u64 {
1386
+ assert ! ( idx < bitmask_len ) ;
1375
1387
match endianess {
1376
1388
Endian :: Little => idx,
1377
- Endian :: Big => len . max ( 8 ) - 1 - idx, // reverse order of bits
1389
+ Endian :: Big => bitmask_len - 1 - idx, // reverse order of bits
1378
1390
}
1379
1391
}
0 commit comments