diff --git a/rust-version b/rust-version index 036282b12f..5bdb8bd836 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5f9dd05862d2e4bceb3be1031b6c936e35671501 +401ae55427522984e4a89c37cff6562a4ddcf6b7 diff --git a/src/machine.rs b/src/machine.rs index 1767a8a745..e91b8d97ef 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -31,6 +31,7 @@ use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{Span, SpanData, Symbol}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use crate::alloc_addresses::EvalContextExt; use crate::concurrency::cpu_affinity::{self, CpuAffinityMask}; @@ -710,9 +711,9 @@ impl<'tcx> MiriMachine<'tcx> { page_size } else { let target = &tcx.sess.target; - match target.arch.as_ref() { - "wasm32" | "wasm64" => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances - "aarch64" => { + match target.arch { + Arch::Wasm32 | Arch::Wasm64 => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances + Arch::AArch64 => { if target.options.vendor.as_ref() == "apple" { // No "definitive" source, but see: // https://www.wwdcnotes.com/notes/wwdc20/10214/ diff --git a/src/shims/alloc.rs b/src/shims/alloc.rs index f498a21c9f..217069b8b5 100644 --- a/src/shims/alloc.rs +++ b/src/shims/alloc.rs @@ -3,6 +3,7 @@ use rustc_ast::expand::allocator::SpecialAllocatorMethod; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use crate::*; @@ -19,14 +20,41 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `library/std/src/sys/alloc/mod.rs` (where this is called `MIN_ALIGN`) and should // be kept in sync. let os = this.tcx.sess.target.os.as_ref(); - let max_fundamental_align = match this.tcx.sess.target.arch.as_ref() { - "riscv32" if matches!(os, "espidf" | "zkvm") => 4, - "xtensa" if matches!(os, "espidf") => 4, - "x86" | "arm" | "m68k" | "csky" | "loongarch32" | "mips" | "mips32r6" | "powerpc" - | "powerpc64" | "sparc" | "wasm32" | "hexagon" | "riscv32" | "xtensa" => 8, - "x86_64" | "aarch64" | "arm64ec" | "loongarch64" | "mips64" | "mips64r6" | "s390x" - | "sparc64" | "riscv64" | "wasm64" => 16, - arch => bug!("unsupported target architecture for malloc: `{}`", arch), + let max_fundamental_align = match &this.tcx.sess.target.arch { + Arch::RiscV32 if matches!(os, "espidf" | "zkvm") => 4, + Arch::Xtensa if matches!(os, "espidf") => 4, + Arch::X86 + | Arch::Arm + | Arch::M68k + | Arch::CSky + | Arch::LoongArch32 + | Arch::Mips + | Arch::Mips32r6 + | Arch::PowerPC + | Arch::PowerPC64 + | Arch::Sparc + | Arch::Wasm32 + | Arch::Hexagon + | Arch::RiscV32 + | Arch::Xtensa => 8, + Arch::X86_64 + | Arch::AArch64 + | Arch::Arm64EC + | Arch::LoongArch64 + | Arch::Mips64 + | Arch::Mips64r6 + | Arch::S390x + | Arch::Sparc64 + | Arch::RiscV64 + | Arch::Wasm64 => 16, + arch @ (Arch::AmdGpu + | Arch::Avr + | Arch::Bpf + | Arch::Msp430 + | Arch::Nvptx64 + | Arch::PowerPC64LE + | Arch::SpirV + | Arch::Unknown(_)) => bug!("unsupported target architecture for malloc: `{arch}`"), }; // The C standard only requires sufficient alignment for any *type* with size less than or // equal to the size requested. Types one can define in standard C seem to never have an alignment diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 54fe27382e..bffe633f77 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -15,6 +15,7 @@ use rustc_middle::{mir, ty}; use rustc_session::config::OomStrategy; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; @@ -799,20 +800,21 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Target-specific shims name if name.starts_with("llvm.x86.") - && (this.tcx.sess.target.arch == "x86" - || this.tcx.sess.target.arch == "x86_64") => + && matches!(this.tcx.sess.target.arch, Arch::X86 | Arch::X86_64) => { return shims::x86::EvalContextExt::emulate_x86_intrinsic( this, link_name, abi, args, dest, ); } - name if name.starts_with("llvm.aarch64.") && this.tcx.sess.target.arch == "aarch64" => { + name if name.starts_with("llvm.aarch64.") + && this.tcx.sess.target.arch == Arch::AArch64 => + { return shims::aarch64::EvalContextExt::emulate_aarch64_intrinsic( this, link_name, abi, args, dest, ); } // FIXME: Move this to an `arm` submodule. - "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => { + "llvm.arm.hint" if this.tcx.sess.target.arch == Arch::Arm => { let [arg] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; // Note that different arguments might have different target feature requirements. diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index c3ca01bbf3..21c9022737 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_abi::{Align, CanonAbi, Size, X86Call}; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use self::shims::windows::handle::{Handle, PseudoHandle}; use crate::shims::os_str::bytes_to_os_str; @@ -140,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768, // x86-32 Windows uses a different calling convention than other Windows targets // for the "system" ABI. - let sys_conv = if this.tcx.sess.target.arch == "x86" { + let sys_conv = if this.tcx.sess.target.arch == Arch::X86 { CanonAbi::X86(X86Call::Stdcall) } else { CanonAbi::C diff --git a/src/shims/x86/bmi.rs b/src/shims/x86/bmi.rs index 140e31cc51..814823d2ac 100644 --- a/src/shims/x86/bmi.rs +++ b/src/shims/x86/bmi.rs @@ -2,6 +2,7 @@ use rustc_abi::CanonAbi; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use crate::*; @@ -31,7 +32,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let target_feature = if unprefixed_name == "bextr" { "bmi1" } else { "bmi2" }; this.expect_target_feature_for_intrinsic(link_name, target_feature)?; - if is_64_bit && this.tcx.sess.target.arch != "x86_64" { + if is_64_bit && this.tcx.sess.target.arch != Arch::X86_64 { return interp_ok(EmulateItemResult::NotSupported); } diff --git a/src/shims/x86/mod.rs b/src/shims/x86/mod.rs index 3324b7b024..91893737b0 100644 --- a/src/shims/x86/mod.rs +++ b/src/shims/x86/mod.rs @@ -5,6 +5,7 @@ use rustc_middle::ty::Ty; use rustc_middle::{mir, ty}; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use self::helpers::bool_to_simd_element; use crate::*; @@ -41,7 +42,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => { - if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != "x86_64" { + if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != Arch::X86_64 { return interp_ok(EmulateItemResult::NotSupported); } @@ -65,7 +66,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.expect_target_feature_for_intrinsic(link_name, "adx")?; let is_u64 = unprefixed_name.ends_with("64"); - if is_u64 && this.tcx.sess.target.arch != "x86_64" { + if is_u64 && this.tcx.sess.target.arch != Arch::X86_64 { return interp_ok(EmulateItemResult::NotSupported); } let [c_in, a, b, out] = diff --git a/src/shims/x86/sse42.rs b/src/shims/x86/sse42.rs index 72c5039a12..aa8aea3558 100644 --- a/src/shims/x86/sse42.rs +++ b/src/shims/x86/sse42.rs @@ -3,6 +3,7 @@ use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::FnAbi; +use rustc_target::spec::Arch; use crate::*; @@ -431,7 +432,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - if bit_size == 64 && this.tcx.sess.target.arch != "x86_64" { + if bit_size == 64 && this.tcx.sess.target.arch != Arch::X86_64 { return interp_ok(EmulateItemResult::NotSupported); } diff --git a/tests/fail/intrinsics/simd_masked_load_element_misaligned.rs b/tests/fail/intrinsics/simd_masked_load_element_misaligned.rs new file mode 100644 index 0000000000..47a51dbbab --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_load_element_misaligned.stderr b/tests/fail/intrinsics/simd_masked_load_element_misaligned.stderr new file mode 100644 index 0000000000..155097cbc0 --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs b/tests/fail/intrinsics/simd_masked_load_vector_misaligned.rs new file mode 100644 index 0000000000..9b1eeaab8d --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_load_vector_misaligned.stderr b/tests/fail/intrinsics/simd_masked_load_vector_misaligned.stderr new file mode 100644 index 0000000000..8dfd1c1b95 --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_store_element_misaligned.rs b/tests/fail/intrinsics/simd_masked_store_element_misaligned.rs new file mode 100644 index 0000000000..b7e23dd1d3 --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_store_element_misaligned.stderr b/tests/fail/intrinsics/simd_masked_store_element_misaligned.stderr new file mode 100644 index 0000000000..7b2ebaaf49 --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs b/tests/fail/intrinsics/simd_masked_store_vector_misaligned.rs new file mode 100644 index 0000000000..8982413e57 --- /dev/null +++ b/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/tests/fail/intrinsics/simd_masked_store_vector_misaligned.stderr b/tests/fail/intrinsics/simd_masked_store_vector_misaligned.stderr new file mode 100644 index 0000000000..7f34e0dcc0 --- /dev/null +++ b/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/tests/pass/intrinsics/portable-simd.rs b/tests/pass/intrinsics/portable-simd.rs index b7d2584c58..4ecbe167b5 100644 --- a/tests/pass/intrinsics/portable-simd.rs +++ b/tests/pass/intrinsics/portable-simd.rs @@ -936,26 +936,93 @@ fn simd_float_intrinsics() { } fn simd_masked_loadstore() { + use intrinsics::*; + // The buffer is deliberarely too short, so reading the last element would be UB. let buf = [3i32; 3]; let default = i32x4::splat(0); let mask = i32x4::from_array([!0, !0, !0, 0]); - let vals = unsafe { intrinsics::simd_masked_load(mask, buf.as_ptr(), default) }; + let vals = + unsafe { simd_masked_load::<_, _, _, { SimdAlign::Element }>(mask, buf.as_ptr(), default) }; assert_eq!(vals, i32x4::from_array([3, 3, 3, 0])); // Also read in a way that the *first* element is OOB. let mask2 = i32x4::from_array([0, !0, !0, !0]); - let vals = - unsafe { intrinsics::simd_masked_load(mask2, buf.as_ptr().wrapping_sub(1), default) }; + let vals = unsafe { + simd_masked_load::<_, _, _, { SimdAlign::Element }>( + mask2, + buf.as_ptr().wrapping_sub(1), + default, + ) + }; assert_eq!(vals, i32x4::from_array([0, 3, 3, 3])); // The buffer is deliberarely too short, so writing the last element would be UB. let mut buf = [42i32; 3]; let vals = i32x4::from_array([1, 2, 3, 4]); - unsafe { intrinsics::simd_masked_store(mask, buf.as_mut_ptr(), vals) }; + unsafe { simd_masked_store::<_, _, _, { SimdAlign::Element }>(mask, buf.as_mut_ptr(), vals) }; assert_eq!(buf, [1, 2, 3]); // Also write in a way that the *first* element is OOB. - unsafe { intrinsics::simd_masked_store(mask2, buf.as_mut_ptr().wrapping_sub(1), vals) }; + unsafe { + simd_masked_store::<_, _, _, { SimdAlign::Element }>( + mask2, + buf.as_mut_ptr().wrapping_sub(1), + vals, + ) + }; 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() {