Move llvm.x86.* implementations into shims::x86

This commit is contained in:
Eduardo Sánchez Muñoz 2023-09-21 19:41:48 +02:00
parent 5ddf866c9c
commit d6b30b88d0
4 changed files with 75 additions and 36 deletions

View File

@ -22,7 +22,7 @@ use rustc_target::{
}; };
use super::backtrace::EvalContextExt as _; use super::backtrace::EvalContextExt as _;
use crate::helpers::{convert::Truncate, target_os_is_unix}; use crate::helpers::target_os_is_unix;
use crate::*; use crate::*;
/// Returned by `emulate_foreign_item_by_name`. /// 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); throw_unsup_format!("unsupported `llvm.prefetch` type argument: {}", ty);
} }
} }
"llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { // FIXME: Move these to an `arm` submodule.
// 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::<u8>(), wide_sum.truncate::<u64>());
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();
}
"llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => {
let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?; 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.") => { name if name.starts_with("llvm.x86.")
return shims::x86::sse::EvalContextExt::emulate_x86_sse_intrinsic( && (this.tcx.sess.target.arch == "x86"
this, link_name, abi, args, dest, || this.tcx.sess.target.arch == "x86_64") =>
); {
} return shims::x86::EvalContextExt::emulate_x86_intrinsic(
name if name.starts_with("llvm.x86.sse2.") => {
return shims::x86::sse2::EvalContextExt::emulate_x86_sse2_intrinsic(
this, link_name, abi, args, dest, this, link_name, abi, args, dest,
); );
} }

View File

@ -1,11 +1,65 @@
use rustc_middle::mir; use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::abi::Size; use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
use crate::*; use crate::*;
use helpers::bool_to_simd_element; use helpers::bool_to_simd_element;
use helpers::convert::Truncate as _;
use shims::foreign_items::EmulateByNameResult;
pub(super) mod sse; mod sse;
pub(super) mod sse2; 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::<u8>(), wide_sum.truncate::<u64>());
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 /// Floating point comparison operation
/// ///

View File

@ -10,7 +10,9 @@ use crate::*;
use shims::foreign_items::EmulateByNameResult; use shims::foreign_items::EmulateByNameResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} 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( fn emulate_x86_sse_intrinsic(
&mut self, &mut self,
link_name: Symbol, link_name: Symbol,

View File

@ -13,7 +13,9 @@ use crate::*;
use shims::foreign_items::EmulateByNameResult; use shims::foreign_items::EmulateByNameResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} 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( fn emulate_x86_sse2_intrinsic(
&mut self, &mut self,
link_name: Symbol, 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)?; 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), _ => return Ok(EmulateByNameResult::NotSupported),
} }
Ok(EmulateByNameResult::NeedsJumping) Ok(EmulateByNameResult::NeedsJumping)