diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index f596df1f7a1..0c92ede40fd 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -22,7 +22,7 @@ use rustc_target::{ }; use super::backtrace::EvalContextExt as _; -use crate::helpers::{convert::Truncate, target_os_is_unix}; +use crate::helpers::target_os_is_unix; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -981,30 +981,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("unsupported `llvm.prefetch` type argument: {}", ty); } } - "llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { - // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. - let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; - let c_in = this.read_scalar(c_in)?.to_u8()?; - let a = this.read_scalar(a)?.to_u64()?; - let b = this.read_scalar(b)?.to_u64()?; - - #[allow(clippy::arithmetic_side_effects)] - // adding two u64 and a u8 cannot wrap in a u128 - let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); - #[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64 - let (c_out, sum) = ((wide_sum >> 64).truncate::(), wide_sum.truncate::()); - - let c_out_field = this.project_field(dest, 0)?; - this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; - let sum_field = this.project_field(dest, 1)?; - this.write_scalar(Scalar::from_u64(sum), &sum_field)?; - } - "llvm.x86.sse2.pause" - if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => - { - let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.yield_active_thread(); - } + // FIXME: Move these to an `arm` submodule. "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; @@ -1055,13 +1032,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } - name if name.starts_with("llvm.x86.sse.") => { - return shims::x86::sse::EvalContextExt::emulate_x86_sse_intrinsic( - this, link_name, abi, args, dest, - ); - } - name if name.starts_with("llvm.x86.sse2.") => { - return shims::x86::sse2::EvalContextExt::emulate_x86_sse2_intrinsic( + name if name.starts_with("llvm.x86.") + && (this.tcx.sess.target.arch == "x86" + || this.tcx.sess.target.arch == "x86_64") => + { + return shims::x86::EvalContextExt::emulate_x86_intrinsic( this, link_name, abi, args, dest, ); } diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index cbdc500be78..16eac81fa0a 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1,11 +1,65 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::Size; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::bool_to_simd_element; +use helpers::convert::Truncate as _; +use shims::foreign_items::EmulateByNameResult; -pub(super) mod sse; -pub(super) mod sse2; +mod sse; +mod sse2; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriInterpCxExt<'mir, 'tcx> +{ + fn emulate_x86_intrinsic( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let this = self.eval_context_mut(); + // Prefix should have already been checked. + let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); + match unprefixed_name { + "addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { + // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. + let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let c_in = this.read_scalar(c_in)?.to_u8()?; + let a = this.read_scalar(a)?.to_u64()?; + let b = this.read_scalar(b)?.to_u64()?; + + #[allow(clippy::arithmetic_side_effects)] + // adding two u64 and a u8 cannot wrap in a u128 + let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); + #[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64 + let (c_out, sum) = ((wide_sum >> 64).truncate::(), wide_sum.truncate::()); + + let c_out_field = this.project_field(dest, 0)?; + this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; + let sum_field = this.project_field(dest, 1)?; + this.write_scalar(Scalar::from_u64(sum), &sum_field)?; + } + + name if name.starts_with("sse.") => { + return sse::EvalContextExt::emulate_x86_sse_intrinsic( + this, link_name, abi, args, dest, + ); + } + name if name.starts_with("sse2.") => { + return sse2::EvalContextExt::emulate_x86_sse2_intrinsic( + this, link_name, abi, args, dest, + ); + } + _ => return Ok(EmulateByNameResult::NotSupported), + } + Ok(EmulateByNameResult::NeedsJumping) + } +} /// Floating point comparison operation /// diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index b6b994b45ac..de1e695b6d1 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -10,7 +10,9 @@ use crate::*; use shims::foreign_items::EmulateByNameResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriInterpCxExt<'mir, 'tcx> +{ fn emulate_x86_sse_intrinsic( &mut self, link_name: Symbol, diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 855ebbe7072..2ca882167bf 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -13,7 +13,9 @@ use crate::*; use shims::foreign_items::EmulateByNameResult; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriInterpCxExt<'mir, 'tcx> +{ fn emulate_x86_sse2_intrinsic( &mut self, link_name: Symbol, @@ -753,6 +755,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_u32(res.try_into().unwrap()), dest)?; } + // Used to implement the `_mm_pause` function. + // The intrinsic is used to hint the processor that the code is in a spin-loop. + "pause" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.yield_active_thread(); + } _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping)