@@ -634,10 +634,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
634634 let ( yes, yes_len) = this. operand_to_simd ( yes) ?;
635635 let ( no, no_len) = this. operand_to_simd ( no) ?;
636636 let ( dest, dest_len) = this. place_to_simd ( dest) ?;
637+ let bitmask_len = dest_len. max ( 8 ) ;
637638
638639 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 ( ) ) ;
641642 assert_eq ! ( dest_len, yes_len) ;
642643 assert_eq ! ( dest_len, no_len) ;
643644
@@ -649,14 +650,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
649650 . unwrap ( ) ;
650651 for i in 0 ..dest_len {
651652 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 ) ) ;
653654 let yes = this. read_immediate ( & this. mplace_index ( & yes, i) ?. into ( ) ) ?;
654655 let no = this. read_immediate ( & this. mplace_index ( & no, i) ?. into ( ) ) ?;
655656 let dest = this. mplace_index ( & dest, i) ?;
656657
657658 let val = if mask != 0 { yes } else { no } ;
658659 this. write_immediate ( * val, & dest. into ( ) ) ?;
659660 }
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+ }
660671 }
661672 #[ rustfmt:: skip]
662673 "simd_cast" | "simd_as" => {
@@ -785,16 +796,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
785796 "simd_bitmask" => {
786797 let & [ ref op] = check_arg_count ( args) ?;
787798 let ( op, op_len) = this. operand_to_simd ( op) ?;
799+ let bitmask_len = op_len. max ( 8 ) ;
788800
789801 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 ( ) ) ;
792804
793805 let mut res = 0u64 ;
794806 for i in 0 ..op_len {
795807 let op = this. read_immediate ( & this. mplace_index ( & op, i) ?. into ( ) ) ?;
796808 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 ) ;
798810 }
799811 }
800812 this. write_int ( res, dest) ?;
@@ -1335,10 +1347,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool
13351347 } )
13361348}
13371349
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 ) ;
13401352 match endianess {
13411353 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
13431355 }
13441356}
0 commit comments