Skip to content

Commit bbe2cf5

Browse files
committed
detect when unused bits of a SIMD bitmask are non-0
1 parent 0a46506 commit bbe2cf5

File tree

3 files changed

+51
-9
lines changed

3 files changed

+51
-9
lines changed

src/shims/intrinsics.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(platform_intrinsics, repr_simd)]
2+
3+
extern "platform-intrinsic" {
4+
fn simd_select_bitmask<M, T>(m: M, yes: T, no: T) -> T;
5+
}
6+
7+
#[repr(simd)]
8+
#[allow(non_camel_case_types)]
9+
#[derive(Copy, Clone)]
10+
struct i32x2(i32, i32);
11+
12+
fn main() { unsafe {
13+
let x = i32x2(0, 1);
14+
simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits
15+
} }
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(platform_intrinsics, repr_simd)]
2+
3+
extern "platform-intrinsic" {
4+
fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
5+
}
6+
7+
#[repr(simd)]
8+
#[allow(non_camel_case_types)]
9+
#[derive(Copy, Clone)]
10+
struct i32x2(i32, i32);
11+
12+
fn main() { unsafe {
13+
let x = i32x2(0, 1);
14+
simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits
15+
} }

0 commit comments

Comments
 (0)