Add implementation of the alignment parameter in Miri
This commit is contained in:
parent
75de619159
commit
ffe6cf6e16
10 changed files with 243 additions and 6 deletions
|
|
@ -1,16 +1,16 @@
|
|||
use either::Either;
|
||||
use rustc_abi::Endian;
|
||||
use rustc_abi::{BackendRepr, Endian};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
use rustc_apfloat::{Float, Round};
|
||||
use rustc_middle::mir::interpret::{InterpErrorKind, UndefinedBehaviorInfo};
|
||||
use rustc_middle::ty::FloatTy;
|
||||
use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo};
|
||||
use rustc_middle::ty::{FloatTy, SimdAlign};
|
||||
use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use tracing::trace;
|
||||
|
||||
use super::{
|
||||
ImmTy, InterpCx, InterpResult, Machine, MinMax, MulAddType, OpTy, PlaceTy, Provenance, Scalar,
|
||||
Size, interp_ok, throw_ub_format,
|
||||
Size, TyAndLayout, assert_matches, interp_ok, throw_ub_format,
|
||||
};
|
||||
use crate::interpret::Writeable;
|
||||
|
||||
|
|
@ -644,6 +644,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
sym::simd_masked_load => {
|
||||
let dest_layout = dest.layout;
|
||||
|
||||
let (mask, mask_len) = self.project_to_simd(&args[0])?;
|
||||
let ptr = self.read_pointer(&args[1])?;
|
||||
let (default, default_len) = self.project_to_simd(&args[2])?;
|
||||
|
|
@ -652,6 +654,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
assert_eq!(dest_len, mask_len);
|
||||
assert_eq!(dest_len, default_len);
|
||||
|
||||
self.check_simd_ptr_alignment(
|
||||
ptr,
|
||||
dest_layout,
|
||||
generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment(),
|
||||
)?;
|
||||
|
||||
for i in 0..dest_len {
|
||||
let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
|
||||
let default = self.read_immediate(&self.project_index(&default, i)?)?;
|
||||
|
|
@ -660,7 +670,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let val = if simd_element_to_bool(mask)? {
|
||||
// Size * u64 is implemented as always checked
|
||||
let ptr = ptr.wrapping_offset(dest.layout.size * i, self);
|
||||
let place = self.ptr_to_mplace(ptr, dest.layout);
|
||||
// we have already checked the alignment requirements
|
||||
let place = self.ptr_to_mplace_unaligned(ptr, dest.layout);
|
||||
self.read_immediate(&place)?
|
||||
} else {
|
||||
default
|
||||
|
|
@ -675,6 +686,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
assert_eq!(mask_len, vals_len);
|
||||
|
||||
self.check_simd_ptr_alignment(
|
||||
ptr,
|
||||
args[2].layout,
|
||||
generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
|
||||
.unwrap_leaf()
|
||||
.to_simd_alignment(),
|
||||
)?;
|
||||
|
||||
for i in 0..vals_len {
|
||||
let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
|
||||
let val = self.read_immediate(&self.project_index(&vals, i)?)?;
|
||||
|
|
@ -682,7 +701,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
if simd_element_to_bool(mask)? {
|
||||
// Size * u64 is implemented as always checked
|
||||
let ptr = ptr.wrapping_offset(val.layout.size * i, self);
|
||||
let place = self.ptr_to_mplace(ptr, val.layout);
|
||||
// we have already checked the alignment requirements
|
||||
let place = self.ptr_to_mplace_unaligned(ptr, val.layout);
|
||||
self.write_immediate(*val, &place)?
|
||||
};
|
||||
}
|
||||
|
|
@ -753,6 +773,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
FloatTy::F128 => self.float_minmax::<Quad>(left, right, op)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn check_simd_ptr_alignment(
|
||||
&self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
vector_layout: TyAndLayout<'tcx>,
|
||||
alignment: SimdAlign,
|
||||
) -> InterpResult<'tcx> {
|
||||
assert_matches!(vector_layout.backend_repr, BackendRepr::SimdVector { .. });
|
||||
|
||||
let align = match alignment {
|
||||
ty::SimdAlign::Unaligned => {
|
||||
// The pointer is supposed to be unaligned, so no check is required.
|
||||
return interp_ok(());
|
||||
}
|
||||
ty::SimdAlign::Element => {
|
||||
// Take the alignment of the only field, which is an array and therefore has the same
|
||||
// alignment as the element type.
|
||||
vector_layout.field(self, 0).align.abi
|
||||
}
|
||||
ty::SimdAlign::Vector => vector_layout.align.abi,
|
||||
};
|
||||
|
||||
self.check_ptr_align(ptr, align)
|
||||
}
|
||||
}
|
||||
|
||||
fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let buf = [0u32; 5];
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
i32x4::splat(-1),
|
||||
// This is not i32-aligned
|
||||
buf.as_ptr().byte_offset(1),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_load_element_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is not i32-aligned
|
||||
LL | | buf.as_ptr().byte_offset(1),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let buf = Simd::<i32, 8>::splat(0);
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
i32x4::splat(-1),
|
||||
// This is i32-aligned but not i32x4-aligned.
|
||||
buf.as_array()[1..].as_ptr(),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is i32-aligned but not i32x4-aligned.
|
||||
LL | | buf.as_array()[1..].as_ptr(),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut buf = [0u32; 5];
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
i32x4::splat(-1),
|
||||
// This is not i32-aligned
|
||||
buf.as_mut_ptr().byte_offset(1),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_store_element_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is not i32-aligned
|
||||
LL | | buf.as_mut_ptr().byte_offset(1),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, portable_simd)]
|
||||
|
||||
use std::intrinsics::simd::*;
|
||||
use std::simd::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mut buf = Simd::<i32, 8>::splat(0);
|
||||
//~v ERROR: accessing memory with alignment
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(
|
||||
i32x4::splat(-1),
|
||||
// This is i32-aligned but not i32x4-aligned.
|
||||
buf.as_mut_array()[1..].as_mut_ptr(),
|
||||
i32x4::splat(0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs:LL:CC
|
||||
|
|
||||
LL | / simd_masked_store::<_, _, _, { SimdAlign::Vector }>(
|
||||
LL | | i32x4::splat(-1),
|
||||
LL | | // This is i32-aligned but not i32x4-aligned.
|
||||
LL | | buf.as_mut_array()[1..].as_mut_ptr(),
|
||||
LL | | i32x4::splat(0),
|
||||
LL | | );
|
||||
| |_________^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -970,6 +970,59 @@ fn simd_masked_loadstore() {
|
|||
)
|
||||
};
|
||||
assert_eq!(buf, [2, 3, 4]);
|
||||
|
||||
// we use a purposely misaliged buffer to make sure Miri doesn't error in this case
|
||||
let buf = [0x03030303_i32; 5];
|
||||
let default = i32x4::splat(0);
|
||||
let mask = i32x4::splat(!0);
|
||||
let vals = unsafe {
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Unaligned }>(
|
||||
mask,
|
||||
buf.as_ptr().byte_offset(1), // this is guaranteed to be unaligned
|
||||
default,
|
||||
)
|
||||
};
|
||||
assert_eq!(vals, i32x4::splat(0x03030303));
|
||||
|
||||
let mut buf = [0i32; 5];
|
||||
let mask = i32x4::splat(!0);
|
||||
unsafe {
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Unaligned }>(
|
||||
mask,
|
||||
buf.as_mut_ptr().byte_offset(1), // this is guaranteed to be unaligned
|
||||
vals,
|
||||
)
|
||||
};
|
||||
assert_eq!(
|
||||
buf,
|
||||
[
|
||||
i32::from_ne_bytes([0, 3, 3, 3]),
|
||||
0x03030303,
|
||||
0x03030303,
|
||||
0x03030303,
|
||||
i32::from_ne_bytes([3, 0, 0, 0])
|
||||
]
|
||||
);
|
||||
|
||||
// `repr(simd)` types like `Simd<T, N>` have the correct alignment for vectors
|
||||
let buf = i32x4::splat(3);
|
||||
let default = i32x4::splat(0);
|
||||
let mask = i32x4::splat(!0);
|
||||
let vals = unsafe {
|
||||
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
|
||||
mask,
|
||||
&raw const buf as *const i32,
|
||||
default,
|
||||
)
|
||||
};
|
||||
assert_eq!(vals, buf);
|
||||
|
||||
let mut buf = i32x4::splat(0);
|
||||
let mask = i32x4::splat(!0);
|
||||
unsafe {
|
||||
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(mask, &raw mut buf as *mut i32, vals)
|
||||
};
|
||||
assert_eq!(buf, vals);
|
||||
}
|
||||
|
||||
fn simd_ops_non_pow2() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue