Skip to content

Commit

Permalink
interpret: do not ICE on padded non-pow2 SIMD vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jun 9, 2024
1 parent 565cadb commit 66d8d6e
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
12 changes: 6 additions & 6 deletions compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,13 +499,13 @@ where
&self,
mplace: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
// Basically we just transmute this place into an array following simd_size_and_type.
// (Transmuting is okay since this is an in-memory place. We also double-check the size
// stays the same.)
// Basically we want to transmute this place into an array following simd_size_and_type.
let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx);
let array = Ty::new_array(self.tcx.tcx, e_ty, len);
let layout = self.layout_of(array)?;
let mplace = mplace.transmute(layout, self)?;
// Some SIMD types have padding, so `len` many `e_ty` does not cover the entire place.
// Therefore we cannot transmute, and instead we project at offset 0, which side-steps
// the size check.
let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, e_ty, len))?;
let mplace = mplace.offset(Size::ZERO, array_layout, self)?;
Ok((mplace, len))
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_const_eval/src/interpret/projection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
ecx: &InterpCx<'tcx, M>,
) -> InterpResult<'tcx, Self> {
assert!(layout.is_sized());
if self.layout().is_sized() {
// Make sure things don't become bigger. Only works if `self` is sized, since
// we can project e.g. from `[u8]` to a `u8` element.
assert!(offset + layout.size <= self.layout().size);
}
self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx)
}

Expand Down
23 changes: 22 additions & 1 deletion src/tools/miri/tests/pass/intrinsics/portable-simd.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-strict-provenance
#![feature(portable_simd, adt_const_params, core_intrinsics)]
#![feature(portable_simd, adt_const_params, core_intrinsics, repr_simd)]
#![allow(incomplete_features, internal_features)]
use std::intrinsics::simd as intrinsics;
use std::ptr;
Expand Down Expand Up @@ -581,11 +581,32 @@ fn simd_masked_loadstore() {
assert_eq!(buf, [2, 3, 4]);
}

fn simd_ops_non_pow2() {
// Just a little smoke test for operations on non-power-of-two vectors.
#[repr(simd, packed)]
#[derive(Copy, Clone)]
pub struct SimdPacked<T, const N: usize>([T; N]);
#[repr(simd)]
#[derive(Copy, Clone)]
pub struct SimdPadded<T, const N: usize>([T; N]);

let x = SimdPacked([1u32; 3]);
let y = SimdPacked([2u32; 3]);
let z = unsafe { intrinsics::simd_add(x, y) };
assert_eq!({ z.0 }, [3u32; 3]);

let x = SimdPadded([1u32; 3]);
let y = SimdPadded([2u32; 3]);
let z = unsafe { intrinsics::simd_add(x, y) };
assert_eq!(z.0, [3u32; 3]);
}

fn main() {
simd_mask();
simd_ops_f32();
simd_ops_f64();
simd_ops_i32();
simd_ops_non_pow2();
simd_cast();
simd_swizzle();
simd_gather_scatter();
Expand Down

0 comments on commit 66d8d6e

Please sign in to comment.