Renamed this arguments to ecx

This commit is contained in:
Yoh Deadfall 2024-11-11 22:31:47 +03:00
parent e2b7027661
commit e43a5c0ac5
12 changed files with 382 additions and 383 deletions

View file

@ -1009,7 +1009,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let this = self.eval_context_ref();
fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
this: &MiriInterpCx<'tcx>,
ecx: &MiriInterpCx<'tcx>,
src: F,
cast_to: TyAndLayout<'tcx>,
round: rustc_apfloat::Round,
@ -1029,7 +1029,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Nothing else
_ =>
span_bug!(
this.cur_span(),
ecx.cur_span(),
"attempted float-to-int conversion with non-int output type {}",
cast_to.ty,
),

View file

@ -730,20 +730,20 @@ impl<'tcx> MiriMachine<'tcx> {
}
pub(crate) fn late_init(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
config: &MiriConfig,
on_main_stack_empty: StackEmptyCallback<'tcx>,
) -> InterpResult<'tcx> {
EnvVars::init(this, config)?;
MiriMachine::init_extern_statics(this)?;
ThreadManager::init(this, on_main_stack_empty);
EnvVars::init(ecx, config)?;
MiriMachine::init_extern_statics(ecx)?;
ThreadManager::init(ecx, on_main_stack_empty);
interp_ok(())
}
pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
pub(crate) fn add_extern_static(ecx: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
// This got just allocated, so there definitely is a pointer here.
let ptr = ptr.into_pointer_or_addr().unwrap();
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
ecx.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
}
pub(crate) fn communicate(&self) -> bool {

View file

@ -195,10 +195,10 @@ impl LiveAllocs<'_, '_> {
}
}
fn remove_unreachable_tags<'tcx>(this: &mut MiriInterpCx<'tcx>, tags: FxHashSet<BorTag>) {
fn remove_unreachable_tags<'tcx>(ecx: &mut MiriInterpCx<'tcx>, tags: FxHashSet<BorTag>) {
// Avoid iterating all allocations if there's no borrow tracker anyway.
if this.machine.borrow_tracker.is_some() {
this.memory.alloc_map().iter(|it| {
if ecx.machine.borrow_tracker.is_some() {
ecx.memory.alloc_map().iter(|it| {
for (_id, (_kind, alloc)) in it {
alloc.extra.borrow_tracker.as_ref().unwrap().remove_unreachable_tags(&tags);
}
@ -206,16 +206,16 @@ fn remove_unreachable_tags<'tcx>(this: &mut MiriInterpCx<'tcx>, tags: FxHashSet<
}
}
fn remove_unreachable_allocs<'tcx>(this: &mut MiriInterpCx<'tcx>, allocs: FxHashSet<AllocId>) {
let allocs = LiveAllocs { ecx: this, collected: allocs };
this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
this.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
this.machine.alloc_addresses.borrow_mut().remove_unreachable_allocs(&allocs);
if let Some(borrow_tracker) = &this.machine.borrow_tracker {
fn remove_unreachable_allocs<'tcx>(ecx: &mut MiriInterpCx<'tcx>, allocs: FxHashSet<AllocId>) {
let allocs = LiveAllocs { ecx, collected: allocs };
ecx.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
ecx.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
ecx.machine.alloc_addresses.borrow_mut().remove_unreachable_allocs(&allocs);
if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs);
}
// Clean up core (non-Miri-specific) state.
this.remove_unreachable_allocs(&allocs.collected);
ecx.remove_unreachable_allocs(&allocs.collected);
}
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}

View file

@ -496,14 +496,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Rust allocation
"__rust_alloc" | "miri_alloc" => {
let default = |this: &mut MiriInterpCx<'tcx>| {
let default = |ecx: &mut MiriInterpCx<'tcx>| {
// Only call `check_shim` when `#[global_allocator]` isn't used. When that
// macro is used, we act like no shim exists, so that the exported function can run.
let [size, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let size = this.read_target_usize(size)?;
let align = this.read_target_usize(align)?;
let [size, align] = ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let size = ecx.read_target_usize(size)?;
let align = ecx.read_target_usize(align)?;
this.check_rustc_alloc_request(size, align)?;
ecx.check_rustc_alloc_request(size, align)?;
let memory_kind = match link_name.as_str() {
"__rust_alloc" => MiriMemoryKind::Rust,
@ -511,13 +511,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
_ => unreachable!(),
};
let ptr = this.allocate_ptr(
let ptr = ecx.allocate_ptr(
Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
memory_kind.into(),
)?;
this.write_pointer(ptr, dest)
ecx.write_pointer(ptr, dest)
};
match link_name.as_str() {
@ -555,14 +555,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
});
}
"__rust_dealloc" | "miri_dealloc" => {
let default = |this: &mut MiriInterpCx<'tcx>| {
let default = |ecx: &mut MiriInterpCx<'tcx>| {
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
let [ptr, old_size, align] =
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let old_size = this.read_target_usize(old_size)?;
let align = this.read_target_usize(align)?;
ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let ptr = ecx.read_pointer(ptr)?;
let old_size = ecx.read_target_usize(old_size)?;
let align = ecx.read_target_usize(align)?;
let memory_kind = match link_name.as_str() {
"__rust_dealloc" => MiriMemoryKind::Rust,
@ -571,7 +571,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
};
// No need to check old_size/align; we anyway check that they match the allocation.
this.deallocate_ptr(
ecx.deallocate_ptr(
ptr,
Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
memory_kind.into(),

View file

@ -8,7 +8,7 @@ use crate::*;
const TASK_COMM_LEN: usize = 16;
pub fn prctl<'tcx>(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
link_name: Symbol,
abi: ExternAbi,
args: &[OpTy<'tcx>],
@ -16,41 +16,41 @@ pub fn prctl<'tcx>(
) -> InterpResult<'tcx> {
// We do not use `check_shim` here because `prctl` is variadic. The argument
// count is checked bellow.
this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
// FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
let pr_set_name = 15;
let pr_get_name = 16;
let [op] = check_min_arg_count("prctl", args)?;
let res = match this.read_scalar(op)?.to_i32()? {
let res = match ecx.read_scalar(op)?.to_i32()? {
op if op == pr_set_name => {
let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
let name = this.read_scalar(name)?;
let thread = this.pthread_self()?;
let name = ecx.read_scalar(name)?;
let thread = ecx.pthread_self()?;
// The Linux kernel silently truncates long names.
// https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
let res =
this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
ecx.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
assert_eq!(res, ThreadNameResult::Ok);
Scalar::from_u32(0)
}
op if op == pr_get_name => {
let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
let name = this.read_scalar(name)?;
let thread = this.pthread_self()?;
let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this);
this.check_ptr_access(
name.to_pointer(this)?,
let name = ecx.read_scalar(name)?;
let thread = ecx.pthread_self()?;
let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx);
ecx.check_ptr_access(
name.to_pointer(ecx)?,
Size::from_bytes(TASK_COMM_LEN),
CheckInAllocMsg::MemoryAccessTest,
)?;
let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
let res = ecx.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
assert_eq!(res, ThreadNameResult::Ok);
Scalar::from_u32(0)
}
op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),
};
this.write_scalar(res, dest)?;
ecx.write_scalar(res, dest)?;
interp_ok(())
}

View file

@ -9,7 +9,7 @@ struct LinuxFutex {
/// Implementation of the SYS_futex syscall.
/// `args` is the arguments *including* the syscall number.
pub fn futex<'tcx>(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
@ -26,19 +26,19 @@ pub fn futex<'tcx>(
// The first three arguments (after the syscall number itself) are the same to all futex operations:
// (int *addr, int op, int val).
// We checked above that these definitely exist.
let addr = this.read_pointer(addr)?;
let op = this.read_scalar(op)?.to_i32()?;
let val = this.read_scalar(val)?.to_i32()?;
let addr = ecx.read_pointer(addr)?;
let op = ecx.read_scalar(op)?.to_i32()?;
let val = ecx.read_scalar(val)?.to_i32()?;
// This is a vararg function so we have to bring our own type for this pointer.
let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32);
let addr = ecx.ptr_to_mplace(addr, ecx.machine.layouts.i32);
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG");
let futex_wait = this.eval_libc_i32("FUTEX_WAIT");
let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET");
let futex_wake = this.eval_libc_i32("FUTEX_WAKE");
let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET");
let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME");
let futex_private = ecx.eval_libc_i32("FUTEX_PRIVATE_FLAG");
let futex_wait = ecx.eval_libc_i32("FUTEX_WAIT");
let futex_wait_bitset = ecx.eval_libc_i32("FUTEX_WAIT_BITSET");
let futex_wake = ecx.eval_libc_i32("FUTEX_WAKE");
let futex_wake_bitset = ecx.eval_libc_i32("FUTEX_WAKE_BITSET");
let futex_realtime = ecx.eval_libc_i32("FUTEX_CLOCK_REALTIME");
// FUTEX_PRIVATE enables an optimization that stops it from working across processes.
// Miri doesn't support that anyway, so we ignore that flag.
@ -57,9 +57,9 @@ pub fn futex<'tcx>(
let (timeout, bitset) = if wait_bitset {
let [_, _, _, _, timeout, uaddr2, bitset] =
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", args)?;
let _timeout = this.read_pointer(timeout)?;
let _uaddr2 = this.read_pointer(uaddr2)?;
(timeout, this.read_scalar(bitset)?.to_u32()?)
let _timeout = ecx.read_pointer(timeout)?;
let _uaddr2 = ecx.read_pointer(uaddr2)?;
(timeout, ecx.read_scalar(bitset)?.to_u32()?)
} else {
let [_, _, _, _, timeout] =
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", args)?;
@ -67,21 +67,21 @@ pub fn futex<'tcx>(
};
if bitset == 0 {
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
}
let timeout = this.deref_pointer_as(timeout, this.libc_ty_layout("timespec"))?;
let timeout = if this.ptr_is_null(timeout.ptr())? {
let timeout = ecx.deref_pointer_as(timeout, ecx.libc_ty_layout("timespec"))?;
let timeout = if ecx.ptr_is_null(timeout.ptr())? {
None
} else {
let duration = match this.read_timespec(&timeout)? {
let duration = match ecx.read_timespec(&timeout)? {
Some(duration) => duration,
None => {
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
}
};
let timeout_clock = if op & futex_realtime == futex_realtime {
this.check_no_isolation(
ecx.check_no_isolation(
"`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`",
)?;
TimeoutClock::RealTime
@ -139,36 +139,36 @@ pub fn futex<'tcx>(
//
// Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to
// do anything special to guarantee fence-load-comparison atomicity.
this.atomic_fence(AtomicFenceOrd::SeqCst)?;
ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
// Read an `i32` through the pointer, regardless of any wrapper types.
// It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
// We do an acquire read -- it only seems reasonable that if we observe a value here, we
// actually establish an ordering with that value.
let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
if val == futex_val {
// The value still matches, so we block the thread and make it wait for FUTEX_WAKE.
// This cannot fail since we already did an atomic acquire read on that pointer.
// Acquire reads are only allowed on mutable memory.
let futex_ref = this
let futex_ref = ecx
.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
.unwrap()
.futex
.clone();
this.futex_wait(
ecx.futex_wait(
futex_ref,
bitset,
timeout,
Scalar::from_target_isize(0, this), // retval_succ
Scalar::from_target_isize(-1, this), // retval_timeout
Scalar::from_target_isize(0, ecx), // retval_succ
Scalar::from_target_isize(-1, ecx), // retval_timeout
dest.clone(),
LibcError("ETIMEDOUT"), // errno_timeout
);
} else {
// The futex value doesn't match the expected value, so we return failure
// right away without sleeping: -1 and errno set to EAGAIN.
return this.set_last_error_and_return(LibcError("EAGAIN"), dest);
return ecx.set_last_error_and_return(LibcError("EAGAIN"), dest);
}
}
// FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
@ -179,42 +179,42 @@ pub fn futex<'tcx>(
// Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
op if op == futex_wake || op == futex_wake_bitset => {
let Some(futex_ref) =
this.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
ecx.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
else {
// No AllocId, or no live allocation at that AllocId.
// Return an error code. (That seems nicer than silently doing something non-intuitive.)
// This means that if an address gets reused by a new allocation,
// we'll use an independent futex queue for this... that seems acceptable.
return this.set_last_error_and_return(LibcError("EFAULT"), dest);
return ecx.set_last_error_and_return(LibcError("EFAULT"), dest);
};
let futex_ref = futex_ref.futex.clone();
let bitset = if op == futex_wake_bitset {
let [_, _, _, _, timeout, uaddr2, bitset] =
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?;
let _timeout = this.read_pointer(timeout)?;
let _uaddr2 = this.read_pointer(uaddr2)?;
this.read_scalar(bitset)?.to_u32()?
let _timeout = ecx.read_pointer(timeout)?;
let _uaddr2 = ecx.read_pointer(uaddr2)?;
ecx.read_scalar(bitset)?.to_u32()?
} else {
u32::MAX
};
if bitset == 0 {
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
}
// Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
// will see the latest value on addr which could be changed by our caller
// before doing the syscall.
this.atomic_fence(AtomicFenceOrd::SeqCst)?;
ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
let mut n = 0;
#[expect(clippy::arithmetic_side_effects)]
for _ in 0..val {
if this.futex_wake(&futex_ref, bitset)? {
if ecx.futex_wake(&futex_ref, bitset)? {
n += 1;
} else {
break;
}
}
this.write_scalar(Scalar::from_target_isize(n, this), dest)?;
ecx.write_scalar(Scalar::from_target_isize(n, ecx), dest)?;
}
op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
}

View file

@ -7,7 +7,7 @@ use crate::shims::unix::linux::sync::futex;
use crate::*;
pub fn syscall<'tcx>(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
link_name: Symbol,
abi: ExternAbi,
args: &[OpTy<'tcx>],
@ -15,18 +15,18 @@ pub fn syscall<'tcx>(
) -> InterpResult<'tcx> {
// We do not use `check_shim` here because `syscall` is variadic. The argument
// count is checked bellow.
this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
// The syscall variadic function is legal to call with more arguments than needed,
// extra arguments are simply ignored. The important check is that when we use an
// argument, we have to also check all arguments *before* it to ensure that they
// have the right type.
let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?;
let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?;
let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?;
let sys_getrandom = ecx.eval_libc("SYS_getrandom").to_target_usize(ecx)?;
let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?;
let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?;
let [op] = check_min_arg_count("syscall", args)?;
match this.read_target_usize(op)? {
match ecx.read_target_usize(op)? {
// `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
// is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
num if num == sys_getrandom => {
@ -34,25 +34,25 @@ pub fn syscall<'tcx>(
// The first argument is the syscall id, so skip over it.
let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
let ptr = ecx.read_pointer(ptr)?;
let len = ecx.read_target_usize(len)?;
// The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
// neither of which have any effect on our current PRNG.
// See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
let _flags = this.read_scalar(flags)?.to_i32()?;
let _flags = ecx.read_scalar(flags)?.to_i32()?;
this.gen_random(ptr, len)?;
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
ecx.gen_random(ptr, len)?;
ecx.write_scalar(Scalar::from_target_usize(len, ecx), dest)?;
}
// `futex` is used by some synchronization primitives.
num if num == sys_futex => {
futex(this, args, dest)?;
futex(ecx, args, dest)?;
}
num if num == sys_eventfd2 => {
let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?;
let result = this.eventfd(initval, flags)?;
this.write_int(result.to_i32()?, dest)?;
let result = ecx.eventfd(initval, flags)?;
ecx.write_int(result.to_i32()?, dest)?;
}
num => {
throw_unsup_format!("syscall: unsupported syscall number {num}");

View file

@ -132,7 +132,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Performs an AES round (given by `f`) on each 128-bit word of
// `state` with the corresponding 128-bit key of `key`.
fn aes_round<'tcx>(
this: &mut crate::MiriInterpCx<'tcx>,
ecx: &mut crate::MiriInterpCx<'tcx>,
state: &OpTy<'tcx>,
key: &OpTy<'tcx>,
dest: &MPlaceTy<'tcx>,
@ -145,21 +145,20 @@ fn aes_round<'tcx>(
assert_eq!(dest.layout.size.bytes() % 16, 0);
let len = dest.layout.size.bytes() / 16;
let u128_array_layout =
this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u128, len))?;
let u128_array_layout = ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u128, len))?;
let state = state.transmute(u128_array_layout, this)?;
let key = key.transmute(u128_array_layout, this)?;
let dest = dest.transmute(u128_array_layout, this)?;
let state = state.transmute(u128_array_layout, ecx)?;
let key = key.transmute(u128_array_layout, ecx)?;
let dest = dest.transmute(u128_array_layout, ecx)?;
for i in 0..len {
let state = this.read_scalar(&this.project_index(&state, i)?)?.to_u128()?;
let key = this.read_scalar(&this.project_index(&key, i)?)?.to_u128()?;
let dest = this.project_index(&dest, i)?;
let state = ecx.read_scalar(&ecx.project_index(&state, i)?)?.to_u128()?;
let key = ecx.read_scalar(&ecx.project_index(&key, i)?)?.to_u128()?;
let dest = ecx.project_index(&dest, i)?;
let res = f(state, key);
this.write_scalar(Scalar::from_u128(res), &dest)?;
ecx.write_scalar(Scalar::from_u128(res), &dest)?;
}
interp_ok(())

View file

@ -75,21 +75,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
/// If `inverse` is set, then the inverse transformation with respect to the reduction polynomial
/// x^8 + x^4 + x^3 + x + 1 is performed instead.
fn affine_transform<'tcx>(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
left: &OpTy<'tcx>,
right: &OpTy<'tcx>,
imm8: &OpTy<'tcx>,
dest: &MPlaceTy<'tcx>,
inverse: bool,
) -> InterpResult<'tcx, ()> {
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
let (left, left_len) = ecx.project_to_simd(left)?;
let (right, right_len) = ecx.project_to_simd(right)?;
let (dest, dest_len) = ecx.project_to_simd(dest)?;
assert_eq!(dest_len, right_len);
assert_eq!(dest_len, left_len);
let imm8 = this.read_scalar(imm8)?.to_u8()?;
let imm8 = ecx.read_scalar(imm8)?.to_u8()?;
// Each 8x8 bit matrix gets multiplied with eight bit vectors.
// Therefore, the iteration is done in chunks of eight.
@ -98,13 +98,13 @@ fn affine_transform<'tcx>(
let mut matrix = [0u8; 8];
for j in 0..8 {
matrix[usize::try_from(j).unwrap()] =
this.read_scalar(&this.project_index(&right, i.wrapping_add(j))?)?.to_u8()?;
ecx.read_scalar(&ecx.project_index(&right, i.wrapping_add(j))?)?.to_u8()?;
}
// Multiply the matrix with the vector and perform the addition.
for j in 0..8 {
let index = i.wrapping_add(j);
let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u8()?;
let left = ecx.read_scalar(&ecx.project_index(&left, index)?)?.to_u8()?;
let left = if inverse { TABLE[usize::from(left)] } else { left };
let mut res = 0;
@ -124,8 +124,8 @@ fn affine_transform<'tcx>(
// Perform the addition.
res ^= imm8;
let dest = this.project_index(&dest, index)?;
this.write_scalar(Scalar::from_u8(res), &dest)?;
let dest = ecx.project_index(&dest, index)?;
ecx.write_scalar(Scalar::from_u8(res), &dest)?;
}
}

File diff suppressed because it is too large Load diff

View file

@ -23,27 +23,27 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap();
fn read<'c>(this: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
fn read<'c>(ecx: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
let mut res = [0; 4];
// We reverse the order because x86 is little endian but the copied implementation uses
// big endian.
for (i, dst) in res.iter_mut().rev().enumerate() {
let projected = &this.project_index(reg, i.try_into().unwrap())?;
*dst = this.read_scalar(projected)?.to_u32()?
let projected = &ecx.project_index(reg, i.try_into().unwrap())?;
*dst = ecx.read_scalar(projected)?.to_u32()?
}
interp_ok(res)
}
fn write<'c>(
this: &mut MiriInterpCx<'c>,
ecx: &mut MiriInterpCx<'c>,
dest: &MPlaceTy<'c>,
val: [u32; 4],
) -> InterpResult<'c, ()> {
// We reverse the order because x86 is little endian but the copied implementation uses
// big endian.
for (i, part) in val.into_iter().rev().enumerate() {
let projected = &this.project_index(dest, i.try_into().unwrap())?;
this.write_scalar(Scalar::from_u32(part), projected)?;
let projected = &ecx.project_index(dest, i.try_into().unwrap())?;
ecx.write_scalar(Scalar::from_u32(part), projected)?;
}
interp_ok(())
}

View file

@ -70,7 +70,7 @@ const USE_SIGNED: u8 = 2;
/// For more information, see the Intel Software Developer's Manual, Vol. 2b, Chapter 4.1.
#[expect(clippy::arithmetic_side_effects)]
fn compare_strings<'tcx>(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
str1: &OpTy<'tcx>,
str2: &OpTy<'tcx>,
len: Option<(u64, u64)>,
@ -80,8 +80,8 @@ fn compare_strings<'tcx>(
let (len1, len2) = if let Some(t) = len {
t
} else {
let len1 = implicit_len(this, str1, imm)?.unwrap_or(default_len);
let len2 = implicit_len(this, str2, imm)?.unwrap_or(default_len);
let len1 = implicit_len(ecx, str1, imm)?.unwrap_or(default_len);
let len2 = implicit_len(ecx, str2, imm)?.unwrap_or(default_len);
(len1, len2)
};
@ -90,12 +90,12 @@ fn compare_strings<'tcx>(
0 => {
// Equal any: Checks which characters of `str2` are inside `str1`.
for i in 0..len2 {
let ch2 = this.read_immediate(&this.project_index(str2, i)?)?;
let ch2 = ecx.read_immediate(&ecx.project_index(str2, i)?)?;
for j in 0..len1 {
let ch1 = this.read_immediate(&this.project_index(str1, j)?)?;
let ch1 = ecx.read_immediate(&ecx.project_index(str1, j)?)?;
let eq = this.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
let eq = ecx.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
if eq.to_scalar().to_bool()? {
result |= 1 << i;
break;
@ -119,9 +119,9 @@ fn compare_strings<'tcx>(
for i in 0..len2 {
for j in (0..len1).step_by(2) {
let ch2 = get_ch(this.read_scalar(&this.project_index(str2, i)?)?)?;
let ch1_1 = get_ch(this.read_scalar(&this.project_index(str1, j)?)?)?;
let ch1_2 = get_ch(this.read_scalar(&this.project_index(str1, j + 1)?)?)?;
let ch2 = get_ch(ecx.read_scalar(&ecx.project_index(str2, i)?)?)?;
let ch1_1 = get_ch(ecx.read_scalar(&ecx.project_index(str1, j)?)?)?;
let ch1_2 = get_ch(ecx.read_scalar(&ecx.project_index(str1, j + 1)?)?)?;
if ch1_1 <= ch2 && ch2 <= ch1_2 {
result |= 1 << i;
@ -135,9 +135,9 @@ fn compare_strings<'tcx>(
result ^= (1 << len1.max(len2)) - 1;
for i in 0..len1.min(len2) {
let ch1 = this.read_immediate(&this.project_index(str1, i)?)?;
let ch2 = this.read_immediate(&this.project_index(str2, i)?)?;
let eq = this.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
let ch1 = ecx.read_immediate(&ecx.project_index(str1, i)?)?;
let ch2 = ecx.read_immediate(&ecx.project_index(str2, i)?)?;
let eq = ecx.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
result |= i32::from(eq.to_scalar().to_bool()?) << i;
}
}
@ -159,9 +159,9 @@ fn compare_strings<'tcx>(
if k >= default_len {
break;
} else {
let ch1 = this.read_immediate(&this.project_index(str1, j)?)?;
let ch2 = this.read_immediate(&this.project_index(str2, k)?)?;
let ne = this.binary_op(mir::BinOp::Ne, &ch1, &ch2)?;
let ch1 = ecx.read_immediate(&ecx.project_index(str1, j)?)?;
let ch2 = ecx.read_immediate(&ecx.project_index(str2, k)?)?;
let ne = ecx.binary_op(mir::BinOp::Ne, &ch1, &ch2)?;
if ne.to_scalar().to_bool()? {
result &= !(1 << i);
@ -198,16 +198,16 @@ fn compare_strings<'tcx>(
/// corresponding to the x86 128-bit integer SIMD type.
fn deconstruct_args<'tcx>(
unprefixed_name: &str,
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
link_name: Symbol,
abi: ExternAbi,
args: &[OpTy<'tcx>],
) -> InterpResult<'tcx, (OpTy<'tcx>, OpTy<'tcx>, Option<(u64, u64)>, u8)> {
let array_layout_fn = |this: &mut MiriInterpCx<'tcx>, imm: u8| {
let array_layout_fn = |ecx: &mut MiriInterpCx<'tcx>, imm: u8| {
if imm & USE_WORDS != 0 {
this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u16, 8))
ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u16, 8))
} else {
this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u8, 16))
ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u8, 16))
}
};
@ -223,26 +223,26 @@ fn deconstruct_args<'tcx>(
if is_explicit {
let [str1, len1, str2, len2, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let imm = this.read_scalar(imm)?.to_u8()?;
ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let default_len = default_len::<u32>(imm);
let len1 = u64::from(this.read_scalar(len1)?.to_u32()?.min(default_len));
let len2 = u64::from(this.read_scalar(len2)?.to_u32()?.min(default_len));
let len1 = u64::from(ecx.read_scalar(len1)?.to_u32()?.min(default_len));
let len2 = u64::from(ecx.read_scalar(len2)?.to_u32()?.min(default_len));
let array_layout = array_layout_fn(this, imm)?;
let str1 = str1.transmute(array_layout, this)?;
let str2 = str2.transmute(array_layout, this)?;
let array_layout = array_layout_fn(ecx, imm)?;
let str1 = str1.transmute(array_layout, ecx)?;
let str2 = str2.transmute(array_layout, ecx)?;
interp_ok((str1, str2, Some((len1, len2)), imm))
} else {
let [str1, str2, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let imm = this.read_scalar(imm)?.to_u8()?;
ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let array_layout = array_layout_fn(this, imm)?;
let str1 = str1.transmute(array_layout, this)?;
let str2 = str2.transmute(array_layout, this)?;
let array_layout = array_layout_fn(ecx, imm)?;
let str1 = str1.transmute(array_layout, ecx)?;
let str2 = str2.transmute(array_layout, ecx)?;
interp_ok((str1, str2, None, imm))
}
@ -251,16 +251,16 @@ fn deconstruct_args<'tcx>(
/// Calculate the c-style string length for a given string `str`.
/// The string is either a length 16 array of bytes a length 8 array of two-byte words.
fn implicit_len<'tcx>(
this: &mut MiriInterpCx<'tcx>,
ecx: &mut MiriInterpCx<'tcx>,
str: &OpTy<'tcx>,
imm: u8,
) -> InterpResult<'tcx, Option<u64>> {
let mut result = None;
let zero = ImmTy::from_int(0, str.layout.field(this, 0));
let zero = ImmTy::from_int(0, str.layout.field(ecx, 0));
for i in 0..default_len::<u64>(imm) {
let ch = this.read_immediate(&this.project_index(str, i)?)?;
let is_zero = this.binary_op(mir::BinOp::Eq, &ch, &zero)?;
let ch = ecx.read_immediate(&ecx.project_index(str, i)?)?;
let is_zero = ecx.binary_op(mir::BinOp::Eq, &ch, &zero)?;
if is_zero.to_scalar().to_bool()? {
result = Some(i);
break;