Skip to content

Commit f347c8d

Browse files
committed
Add implementation of the alignment parameter in Miri
1 parent 7d78b5f commit f347c8d

10 files changed

+252
-7
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use either::Either;
2-
use rustc_abi::Endian;
2+
use rustc_abi::{BackendRepr, Endian};
33
use rustc_apfloat::{Float, Round};
4-
use rustc_middle::mir::interpret::{InterpErrorKind, UndefinedBehaviorInfo};
5-
use rustc_middle::ty::FloatTy;
4+
use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo};
5+
use rustc_middle::ty::{FloatTy, SimdAlign};
66
use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty};
77
use rustc_span::{Symbol, sym};
88
use tracing::trace;
99

1010
use super::{
11-
ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Provenance, Scalar, Size, interp_ok,
12-
throw_ub_format,
11+
ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Provenance, Scalar, Size, TyAndLayout,
12+
assert_matches, interp_ok, throw_ub_format,
1313
};
1414
use crate::interpret::Writeable;
1515

@@ -658,6 +658,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
658658
}
659659
}
660660
sym::simd_masked_load => {
661+
let dest_layout = dest.layout;
662+
661663
let (mask, mask_len) = self.project_to_simd(&args[0])?;
662664
let ptr = self.read_pointer(&args[1])?;
663665
let (default, default_len) = self.project_to_simd(&args[2])?;
@@ -666,6 +668,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
666668
assert_eq!(dest_len, mask_len);
667669
assert_eq!(dest_len, default_len);
668670

671+
self.check_simd_ptr_alignment(
672+
ptr,
673+
dest_layout,
674+
generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
675+
.unwrap_leaf()
676+
.to_simd_alignment(),
677+
)?;
678+
669679
for i in 0..dest_len {
670680
let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
671681
let default = self.read_immediate(&self.project_index(&default, i)?)?;
@@ -674,7 +684,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
674684
let val = if simd_element_to_bool(mask)? {
675685
// Size * u64 is implemented as always checked
676686
let ptr = ptr.wrapping_offset(dest.layout.size * i, self);
677-
let place = self.ptr_to_mplace(ptr, dest.layout);
687+
// we have already checked the alignment requirements
688+
let place = self.ptr_to_mplace_unaligned(ptr, dest.layout);
678689
self.read_immediate(&place)?
679690
} else {
680691
default
@@ -689,14 +700,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
689700

690701
assert_eq!(mask_len, vals_len);
691702

703+
self.check_simd_ptr_alignment(
704+
ptr,
705+
args[2].layout,
706+
generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0]
707+
.unwrap_leaf()
708+
.to_simd_alignment(),
709+
)?;
710+
692711
for i in 0..vals_len {
693712
let mask = self.read_immediate(&self.project_index(&mask, i)?)?;
694713
let val = self.read_immediate(&self.project_index(&vals, i)?)?;
695714

696715
if simd_element_to_bool(mask)? {
697716
// Size * u64 is implemented as always checked
698717
let ptr = ptr.wrapping_offset(val.layout.size * i, self);
699-
let place = self.ptr_to_mplace(ptr, val.layout);
718+
// we have already checked the alignment requirements
719+
let place = self.ptr_to_mplace_unaligned(ptr, val.layout);
700720
self.write_immediate(*val, &place)?
701721
};
702722
}
@@ -748,6 +768,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
748768
FloatTy::F128 => unimplemented!("f16_f128"),
749769
})
750770
}
771+
772+
fn check_simd_ptr_alignment(
773+
&self,
774+
ptr: Pointer<Option<M::Provenance>>,
775+
vector_layout: TyAndLayout<'tcx>,
776+
alignment: SimdAlign,
777+
) -> InterpResult<'tcx> {
778+
assert_matches!(vector_layout.backend_repr, BackendRepr::SimdVector { .. });
779+
780+
let layout = match alignment {
781+
ty::SimdAlign::Unaligned => {
782+
// The pointer is supposed to be unaligned, so no check is required.
783+
return interp_ok(());
784+
}
785+
ty::SimdAlign::Element => {
786+
// Take the alignment of the only field, which is an array and therefore has the same
787+
// alignment as the element type.
788+
vector_layout.field(self, 0)
789+
}
790+
ty::SimdAlign::Vector => vector_layout,
791+
};
792+
793+
self.check_ptr_align(ptr, layout.align.abi)
794+
}
751795
}
752796

753797
fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(core_intrinsics, portable_simd)]
2+
3+
use std::intrinsics::simd::*;
4+
use std::simd::*;
5+
6+
fn main() {
7+
unsafe {
8+
let buf = [0u32; 5];
9+
//~v ERROR: accessing memory with alignment
10+
simd_masked_load::<_, _, _, { SimdAlign::Element }>(
11+
i32x4::splat(-1),
12+
// This is not i32-aligned
13+
buf.as_ptr().byte_offset(1),
14+
i32x4::splat(0),
15+
);
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
2+
--> tests/fail/intrinsics/simd_masked_load_element_misaligned.rs:LL:CC
3+
|
4+
LL | / simd_masked_load::<_, _, _, { SimdAlign::Element }>(
5+
LL | | i32x4::splat(-1),
6+
LL | | // This is not i32-aligned
7+
LL | | buf.as_ptr().byte_offset(1),
8+
LL | | i32x4::splat(0),
9+
LL | | );
10+
| |_________^ Undefined Behavior occurred here
11+
|
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE:
15+
= note: inside `main` at tests/fail/intrinsics/simd_masked_load_element_misaligned.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(core_intrinsics, portable_simd)]
2+
3+
use std::intrinsics::simd::*;
4+
use std::simd::*;
5+
6+
fn main() {
7+
unsafe {
8+
let buf = Simd::<i32, 8>::splat(0);
9+
//~v ERROR: accessing memory with alignment
10+
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
11+
i32x4::splat(-1),
12+
// This is i32-aligned but not i32x4-aligned.
13+
buf.as_array()[1..].as_ptr(),
14+
i32x4::splat(0),
15+
);
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
2+
--> tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs:LL:CC
3+
|
4+
LL | / simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
5+
LL | | i32x4::splat(-1),
6+
LL | | // This is i32-aligned but not i32x4-aligned.
7+
LL | | buf.as_array()[1..].as_ptr(),
8+
LL | | i32x4::splat(0),
9+
LL | | );
10+
| |_________^ Undefined Behavior occurred here
11+
|
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE:
15+
= note: inside `main` at tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(core_intrinsics, portable_simd)]
2+
3+
use std::intrinsics::simd::*;
4+
use std::simd::*;
5+
6+
fn main() {
7+
unsafe {
8+
let mut buf = [0u32; 5];
9+
//~v ERROR: accessing memory with alignment
10+
simd_masked_store::<_, _, _, { SimdAlign::Element }>(
11+
i32x4::splat(-1),
12+
// This is not i32-aligned
13+
buf.as_mut_ptr().byte_offset(1),
14+
i32x4::splat(0),
15+
);
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
2+
--> tests/fail/intrinsics/simd_masked_store_element_misaligned.rs:LL:CC
3+
|
4+
LL | / simd_masked_store::<_, _, _, { SimdAlign::Element }>(
5+
LL | | i32x4::splat(-1),
6+
LL | | // This is not i32-aligned
7+
LL | | buf.as_mut_ptr().byte_offset(1),
8+
LL | | i32x4::splat(0),
9+
LL | | );
10+
| |_________^ Undefined Behavior occurred here
11+
|
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE:
15+
= note: inside `main` at tests/fail/intrinsics/simd_masked_store_element_misaligned.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(core_intrinsics, portable_simd)]
2+
3+
use std::intrinsics::simd::*;
4+
use std::simd::*;
5+
6+
fn main() {
7+
unsafe {
8+
let mut buf = Simd::<i32, 8>::splat(0);
9+
//~v ERROR: accessing memory with alignment
10+
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(
11+
i32x4::splat(-1),
12+
// This is i32-aligned but not i32x4-aligned.
13+
buf.as_mut_array()[1..].as_mut_ptr(),
14+
i32x4::splat(0),
15+
);
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
2+
--> tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs:LL:CC
3+
|
4+
LL | / simd_masked_store::<_, _, _, { SimdAlign::Vector }>(
5+
LL | | i32x4::splat(-1),
6+
LL | | // This is i32-aligned but not i32x4-aligned.
7+
LL | | buf.as_mut_array()[1..].as_mut_ptr(),
8+
LL | | i32x4::splat(0),
9+
LL | | );
10+
| |_________^ Undefined Behavior occurred here
11+
|
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE:
15+
= note: inside `main` at tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+

src/tools/miri/tests/pass/intrinsics/portable-simd.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,59 @@ fn simd_masked_loadstore() {
714714
)
715715
};
716716
assert_eq!(buf, [2, 3, 4]);
717+
718+
// we use a purposely misaliged buffer to make sure Miri doesn't error in this case
719+
let buf = [0x03030303_i32; 5];
720+
let default = i32x4::splat(0);
721+
let mask = i32x4::splat(!0);
722+
let vals = unsafe {
723+
simd_masked_load::<_, _, _, { SimdAlign::Unaligned }>(
724+
mask,
725+
buf.as_ptr().byte_offset(1), // this is guaranteed to be unaligned
726+
default,
727+
)
728+
};
729+
assert_eq!(vals, i32x4::splat(0x03030303));
730+
731+
let mut buf = [0i32; 5];
732+
let mask = i32x4::splat(!0);
733+
unsafe {
734+
simd_masked_store::<_, _, _, { SimdAlign::Unaligned }>(
735+
mask,
736+
buf.as_mut_ptr().byte_offset(1), // this is guaranteed to be unaligned
737+
vals,
738+
)
739+
};
740+
assert_eq!(
741+
buf,
742+
[
743+
i32::from_ne_bytes([0, 3, 3, 3]),
744+
0x03030303,
745+
0x03030303,
746+
0x03030303,
747+
i32::from_ne_bytes([3, 0, 0, 0])
748+
]
749+
);
750+
751+
// `repr(simd)` types like `Simd<T, N>` have the correct alignment for vectors
752+
let buf = i32x4::splat(3);
753+
let default = i32x4::splat(0);
754+
let mask = i32x4::splat(!0);
755+
let vals = unsafe {
756+
simd_masked_load::<_, _, _, { SimdAlign::Vector }>(
757+
mask,
758+
&raw const buf as *const i32,
759+
default,
760+
)
761+
};
762+
assert_eq!(vals, buf);
763+
764+
let mut buf = i32x4::splat(0);
765+
let mask = i32x4::splat(!0);
766+
unsafe {
767+
simd_masked_store::<_, _, _, { SimdAlign::Vector }>(mask, &raw mut buf as *mut i32, vals)
768+
};
769+
assert_eq!(buf, vals);
717770
}
718771

719772
fn simd_ops_non_pow2() {

0 commit comments

Comments
 (0)