From ffe6cf6e166cf1512576d4a17df6c51aa0063c24 Mon Sep 17 00:00:00 2001 From: sayantn Date: Thu, 9 Oct 2025 22:39:48 +0530 Subject: [PATCH] Add implementation of the alignment parameter in Miri --- .../src/interpret/intrinsics/simd.rs | 56 +++++++++++++++++-- .../simd_masked_load_element_misaligned.rs | 17 ++++++ ...simd_masked_load_element_misaligned.stderr | 18 ++++++ .../simd_masked_load_vector_misaligned.rs | 17 ++++++ .../simd_masked_load_vector_misaligned.stderr | 18 ++++++ .../simd_masked_store_element_misaligned.rs | 17 ++++++ ...imd_masked_store_element_misaligned.stderr | 18 ++++++ .../simd_masked_store_vector_misaligned.rs | 17 ++++++ ...simd_masked_store_vector_misaligned.stderr | 18 ++++++ .../tests/pass/intrinsics/portable-simd.rs | 53 ++++++++++++++++++ 10 files changed, 243 insertions(+), 6 deletions(-) create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.stderr diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index f97bdf627ed9..751674f3f068 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -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::(left, right, op)?, }) } + + fn check_simd_ptr_alignment( + &self, + ptr: Pointer>, + 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 { diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.rs b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.rs new file mode 100644 index 000000000000..3b5e389cf27e --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.rs @@ -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), + ); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.stderr b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.stderr new file mode 100644 index 000000000000..155097cbc0e8 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_element_misaligned.stderr @@ -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 + diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs new file mode 100644 index 000000000000..9b1eeaab8d2f --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics, portable_simd)] + +use std::intrinsics::simd::*; +use std::simd::*; + +fn main() { + unsafe { + let buf = Simd::::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), + ); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.stderr b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.stderr new file mode 100644 index 000000000000..8dfd1c1b95da --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_load_vector_misaligned.stderr @@ -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 + diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.rs b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.rs new file mode 100644 index 000000000000..b7e23dd1d3b3 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.rs @@ -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), + ); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.stderr b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.stderr new file mode 100644 index 000000000000..7b2ebaaf495c --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_element_misaligned.stderr @@ -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 + diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs new file mode 100644 index 000000000000..8982413e57ee --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics, portable_simd)] + +use std::intrinsics::simd::*; +use std::simd::*; + +fn main() { + unsafe { + let mut buf = Simd::::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), + ); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.stderr b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.stderr new file mode 100644 index 000000000000..7f34e0dcc0db --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/simd_masked_store_vector_misaligned.stderr @@ -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 + diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index faf79fc1a8d1..4ecbe167b525 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -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` 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() {