interpret, miri: uniform treatments of intrinsics/functions with and without return block

This commit is contained in:
Ralf Jung 2024-05-04 17:39:29 +02:00
parent d7ea27808d
commit 8e4466497f
24 changed files with 192 additions and 240 deletions

View File

@ -467,19 +467,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
let intrinsic_name = ecx.tcx.item_name(instance.def_id()); let intrinsic_name = ecx.tcx.item_name(instance.def_id());
// CTFE-specific intrinsics. // CTFE-specific intrinsics.
let Some(ret) = target else {
// Handle diverging intrinsics. We can't handle any of them (that are not already
// handled above), but check if there is a fallback body.
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
throw_unsup_format!(
"intrinsic `{intrinsic_name}` is not supported at compile-time"
);
}
return Ok(Some(ty::Instance {
def: ty::InstanceDef::Item(instance.def_id()),
args: instance.args,
}));
};
match intrinsic_name { match intrinsic_name {
sym::ptr_guaranteed_cmp => { sym::ptr_guaranteed_cmp => {
let a = ecx.read_scalar(&args[0])?; let a = ecx.read_scalar(&args[0])?;
@ -559,7 +546,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
} }
} }
ecx.go_to_block(ret); // Intrinsic is done, jump to next block.
ecx.return_to_block(target)?;
Ok(None) Ok(None)
} }

View File

@ -113,10 +113,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, bool> { ) -> InterpResult<'tcx, bool> {
let instance_args = instance.args; let instance_args = instance.args;
let intrinsic_name = self.tcx.item_name(instance.def_id()); let intrinsic_name = self.tcx.item_name(instance.def_id());
let Some(ret) = ret else {
// We don't support any intrinsic without return place.
return Ok(false);
};
match intrinsic_name { match intrinsic_name {
sym::caller_location => { sym::caller_location => {
@ -376,7 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}; };
M::panic_nounwind(self, &msg)?; M::panic_nounwind(self, &msg)?;
// Skip the `go_to_block` at the end. // Skip the `return_to_block` at the end (we panicked, we do not return).
return Ok(true); return Ok(true);
} }
} }
@ -437,11 +433,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
} }
// Unsupported intrinsic: skip the return_to_block below.
_ => return Ok(false), _ => return Ok(false),
} }
trace!("{:?}", self.dump_place(&dest.clone().into())); trace!("{:?}", self.dump_place(&dest.clone().into()));
self.go_to_block(ret); self.return_to_block(ret)?;
Ok(true) Ok(true)
} }

View File

@ -95,6 +95,7 @@ pub use rustc_const_eval::interpret::*;
#[doc(no_inline)] #[doc(no_inline)]
pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _};
pub use crate::shims::EmulateItemResult;
pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _};
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _;

View File

@ -4,7 +4,6 @@ use rustc_ast::expand::allocator::AllocatorKind;
use rustc_target::abi::{Align, Size}; use rustc_target::abi::{Align, Size};
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
/// Check some basic requirements for this allocation request: /// Check some basic requirements for this allocation request:
/// non-zero size, power-of-two alignment. /// non-zero size, power-of-two alignment.
@ -55,12 +54,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn emulate_allocator( fn emulate_allocator(
&mut self, &mut self,
default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>, default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let Some(allocator_kind) = this.tcx.allocator_kind(()) else { let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
// in real code, this symbol does not exist without an allocator // in real code, this symbol does not exist without an allocator
return Ok(EmulateForeignItemResult::NotSupported); return Ok(EmulateItemResult::NotSupported);
}; };
match allocator_kind { match allocator_kind {
@ -70,11 +69,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// and not execute any Miri shim. Somewhat unintuitively doing so is done // and not execute any Miri shim. Somewhat unintuitively doing so is done
// by returning `NotSupported`, which triggers the `lookup_exported_symbol` // by returning `NotSupported`, which triggers the `lookup_exported_symbol`
// fallback case in `emulate_foreign_item`. // fallback case in `emulate_foreign_item`.
return Ok(EmulateForeignItemResult::NotSupported); return Ok(EmulateItemResult::NotSupported);
} }
AllocatorKind::Default => { AllocatorKind::Default => {
default(this)?; default(this)?;
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }
} }

View File

@ -28,16 +28,6 @@ impl DynSym {
} }
} }
/// Returned by `emulate_foreign_item_inner`.
pub enum EmulateForeignItemResult {
/// The caller is expected to jump to the return block.
NeedsJumping,
/// Jumping has already been taken care of.
AlreadyJumped,
/// The item is not supported.
NotSupported,
}
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 trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Emulates calling a foreign item, failing if the item is not supported. /// Emulates calling a foreign item, failing if the item is not supported.
@ -58,84 +48,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let tcx = this.tcx.tcx; let tcx = this.tcx.tcx;
// First: functions that diverge. // Some shims forward to other MIR bodies.
let ret = match ret { match link_name.as_str() {
None => // This matches calls to the foreign item `panic_impl`.
match link_name.as_str() { // The implementation is provided by the function with the `#[panic_handler]` attribute.
"miri_start_unwind" => { "panic_impl" => {
// `check_shim` happens inside `handle_miri_start_unwind`. // We don't use `check_shim` here because we are just forwarding to the lang
this.handle_miri_start_unwind(abi, link_name, args, unwind)?; // item. Argument count checking will be performed when the returned `Body` is
return Ok(None); // called.
} this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
// This matches calls to the foreign item `panic_impl`. let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
// The implementation is provided by the function with the `#[panic_handler]` attribute. let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
"panic_impl" => { return Ok(Some((
// We don't use `check_shim` here because we are just forwarding to the lang this.load_mir(panic_impl_instance.def, None)?,
// item. Argument count checking will be performed when the returned `Body` is panic_impl_instance,
// called. )));
this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
return Ok(Some((
this.load_mir(panic_impl_instance.def, None)?,
panic_impl_instance,
)));
}
"__rust_alloc_error_handler" => {
// Forward to the right symbol that implements this function.
let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
// in real code, this symbol does not exist without an allocator
throw_unsup_format!(
"`__rust_alloc_error_handler` cannot be called when no alloc error handler is set"
);
};
let name = alloc_error_handler_name(handler_kind);
let handler = this
.lookup_exported_symbol(Symbol::intern(name))?
.expect("missing alloc error handler symbol");
return Ok(Some(handler));
}
#[rustfmt::skip]
| "exit"
| "ExitProcess"
=> {
let exp_abi = if link_name.as_str() == "exit" {
Abi::C { unwind: false }
} else {
Abi::System { unwind: false }
};
let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
}
"abort" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
))
}
_ => {
if let Some(body) = this.lookup_exported_symbol(link_name)? {
return Ok(Some(body));
}
this.handle_unsupported(format!(
"can't call (diverging) foreign function: {link_name}"
))?;
return Ok(None);
}
},
Some(p) => p,
};
// Second: functions that return immediately.
match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
EmulateForeignItemResult::NeedsJumping => {
trace!("{:?}", this.dump_place(&dest.clone().into()));
this.go_to_block(ret);
} }
EmulateForeignItemResult::AlreadyJumped => (), "__rust_alloc_error_handler" => {
EmulateForeignItemResult::NotSupported => { // Forward to the right symbol that implements this function.
let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
// in real code, this symbol does not exist without an allocator
throw_unsup_format!(
"`__rust_alloc_error_handler` cannot be called when no alloc error handler is set"
);
};
let name = alloc_error_handler_name(handler_kind);
let handler = this
.lookup_exported_symbol(Symbol::intern(name))?
.expect("missing alloc error handler symbol");
return Ok(Some(handler));
}
_ => {}
}
// The rest either implements the logic, or falls back to `lookup_exported_symbol`.
match this.emulate_foreign_item_inner(link_name, abi, args, dest, unwind)? {
EmulateItemResult::NeedsJumping => {
trace!("{:?}", this.dump_place(&dest.clone().into()));
this.return_to_block(ret)?;
}
EmulateItemResult::AlreadyJumped => (),
EmulateItemResult::NotSupported => {
if let Some(body) = this.lookup_exported_symbol(link_name)? { if let Some(body) = this.lookup_exported_symbol(link_name)? {
return Ok(Some(body)); return Ok(Some(body));
} }
@ -243,7 +196,8 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { unwind: mir::UnwindAction,
) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// First deal with any external C functions in linked .so file. // First deal with any external C functions in linked .so file.
@ -254,7 +208,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// by the specified `.so` file; we should continue and check if it corresponds to // by the specified `.so` file; we should continue and check if it corresponds to
// a provided shim. // a provided shim.
if this.call_external_c_fct(link_name, dest, args)? { if this.call_external_c_fct(link_name, dest, args)? {
return Ok(EmulateForeignItemResult::NeedsJumping); return Ok(EmulateItemResult::NeedsJumping);
} }
} }
@ -298,6 +252,11 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// shim, add it to the corresponding submodule. // shim, add it to the corresponding submodule.
match link_name.as_str() { match link_name.as_str() {
// Miri-specific extern functions // Miri-specific extern functions
"miri_start_unwind" => {
// `check_shim` happens inside `handle_miri_start_unwind`.
this.handle_miri_start_unwind(abi, link_name, args, unwind)?;
return Ok(EmulateItemResult::AlreadyJumped);
}
"miri_run_provenance_gc" => { "miri_run_provenance_gc" => {
let [] = this.check_shim(abi, Abi::Rust, link_name, args)?; let [] = this.check_shim(abi, Abi::Rust, link_name, args)?;
this.run_provenance_gc(); this.run_provenance_gc();
@ -362,29 +321,24 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Return value: 0 on success, otherwise the size it would have needed. // Return value: 0 on success, otherwise the size it would have needed.
this.write_int(if success { 0 } else { needed_size }, dest)?; this.write_int(if success { 0 } else { needed_size }, dest)?;
} }
// Obtains the size of a Miri backtrace. See the README for details. // Obtains the size of a Miri backtrace. See the README for details.
"miri_backtrace_size" => { "miri_backtrace_size" => {
this.handle_miri_backtrace_size(abi, link_name, args, dest)?; this.handle_miri_backtrace_size(abi, link_name, args, dest)?;
} }
// Obtains a Miri backtrace. See the README for details. // Obtains a Miri backtrace. See the README for details.
"miri_get_backtrace" => { "miri_get_backtrace" => {
// `check_shim` happens inside `handle_miri_get_backtrace`. // `check_shim` happens inside `handle_miri_get_backtrace`.
this.handle_miri_get_backtrace(abi, link_name, args, dest)?; this.handle_miri_get_backtrace(abi, link_name, args, dest)?;
} }
// Resolves a Miri backtrace frame. See the README for details. // Resolves a Miri backtrace frame. See the README for details.
"miri_resolve_frame" => { "miri_resolve_frame" => {
// `check_shim` happens inside `handle_miri_resolve_frame`. // `check_shim` happens inside `handle_miri_resolve_frame`.
this.handle_miri_resolve_frame(abi, link_name, args, dest)?; this.handle_miri_resolve_frame(abi, link_name, args, dest)?;
} }
// Writes the function and file names of a Miri backtrace frame into a user provided buffer. See the README for details. // Writes the function and file names of a Miri backtrace frame into a user provided buffer. See the README for details.
"miri_resolve_frame_names" => { "miri_resolve_frame_names" => {
this.handle_miri_resolve_frame_names(abi, link_name, args)?; this.handle_miri_resolve_frame_names(abi, link_name, args)?;
} }
// Writes some bytes to the interpreter's stdout/stderr. See the // Writes some bytes to the interpreter's stdout/stderr. See the
// README for details. // README for details.
"miri_write_to_stdout" | "miri_write_to_stderr" => { "miri_write_to_stdout" | "miri_write_to_stderr" => {
@ -398,7 +352,6 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => unreachable!(), _ => unreachable!(),
}; };
} }
// Promises that a pointer has a given symbolic alignment. // Promises that a pointer has a given symbolic alignment.
"miri_promise_symbolic_alignment" => { "miri_promise_symbolic_alignment" => {
use rustc_target::abi::AlignFromBytesError; use rustc_target::abi::AlignFromBytesError;
@ -442,6 +395,25 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
} }
// Aborting the process.
"exit" | "ExitProcess" => {
let exp_abi = if link_name.as_str() == "exit" {
Abi::C { unwind: false }
} else {
Abi::System { unwind: false }
};
let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
}
"abort" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
))
}
// Standard C allocation // Standard C allocation
"malloc" => { "malloc" => {
let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -504,7 +476,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"__rust_alloc" => return this.emulate_allocator(default), "__rust_alloc" => return this.emulate_allocator(default),
"miri_alloc" => { "miri_alloc" => {
default(this)?; default(this)?;
return Ok(EmulateForeignItemResult::NeedsJumping); return Ok(EmulateItemResult::NeedsJumping);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -564,7 +536,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
"miri_dealloc" => { "miri_dealloc" => {
default(this)?; default(this)?;
return Ok(EmulateForeignItemResult::NeedsJumping); return Ok(EmulateItemResult::NeedsJumping);
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -966,11 +938,11 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner( shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner(
this, link_name, abi, args, dest, this, link_name, abi, args, dest,
), ),
_ => Ok(EmulateForeignItemResult::NotSupported), _ => Ok(EmulateItemResult::NotSupported),
}, },
}; };
// We only fall through to here if we did *not* hit the `_` arm above, // We only fall through to here if we did *not* hit the `_` arm above,
// i.e., if we actually emulated the function with one of the shims. // i.e., if we actually emulated the function with one of the shims.
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
intrinsic_name: &str, intrinsic_name: &str,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, bool> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect(); let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect();
@ -114,9 +114,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?;
} }
_ => return Ok(false), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(true) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -10,8 +10,8 @@ use rustc_middle::{
mir, mir,
ty::{self, FloatTy}, ty::{self, FloatTy},
}; };
use rustc_target::abi::Size;
use rustc_span::{sym, Symbol}; use rustc_span::{sym, Symbol};
use rustc_target::abi::Size;
use crate::*; use crate::*;
use atomic::EvalContextExt as _; use atomic::EvalContextExt as _;
@ -37,51 +37,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = this.tcx.item_name(instance.def_id());
let intrinsic_name = intrinsic_name.as_str(); let intrinsic_name = intrinsic_name.as_str();
// Handle intrinsics without return place. match this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, dest, ret)? {
match intrinsic_name { EmulateItemResult::NotSupported => {
"abort" => { // We haven't handled the intrinsic, let's see if we can use a fallback body.
throw_machine_stop!(TerminationInfo::Abort( if this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
"the program aborted execution".to_owned() throw_unsup_format!("unimplemented intrinsic: `{intrinsic_name}`")
)) }
let intrinsic_fallback_checks_ub = Symbol::intern("intrinsic_fallback_checks_ub");
if this
.tcx
.get_attrs_by_path(
instance.def_id(),
&[sym::miri, intrinsic_fallback_checks_ub],
)
.next()
.is_none()
{
throw_unsup_format!(
"miri can only use intrinsic fallback bodies that check UB. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_checks_ub]` attribute to it; also ping @rust-lang/miri when you do that"
);
}
Ok(Some(ty::Instance {
def: ty::InstanceDef::Item(instance.def_id()),
args: instance.args,
}))
} }
_ => {} EmulateItemResult::NeedsJumping => {
trace!("{:?}", this.dump_place(&dest.clone().into()));
this.return_to_block(ret)?;
Ok(None)
}
EmulateItemResult::AlreadyJumped => Ok(None),
} }
// All remaining supported intrinsics have a return place.
let ret = match ret {
// FIXME: add fallback body support once we actually have a diverging intrinsic with a fallback body
None => throw_unsup_format!("unimplemented (diverging) intrinsic: `{intrinsic_name}`"),
Some(p) => p,
};
// Some intrinsics are special and need the "ret".
match intrinsic_name {
"catch_unwind" => {
this.handle_catch_unwind(args, dest, ret)?;
return Ok(None);
}
_ => {}
}
// The rest jumps to `ret` immediately.
if !this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, dest)? {
// We haven't handled the intrinsic, let's see if we can use a fallback body.
if this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
throw_unsup_format!("unimplemented intrinsic: `{intrinsic_name}`")
}
let intrinsic_fallback_checks_ub = Symbol::intern("intrinsic_fallback_checks_ub");
if this.tcx.get_attrs_by_path(instance.def_id(), &[sym::miri, intrinsic_fallback_checks_ub]).next().is_none() {
throw_unsup_format!("miri can only use intrinsic fallback bodies that check UB. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_checks_ub]` attribute to it; also ping @rust-lang/miri when you do that");
}
return Ok(Some(ty::Instance {
def: ty::InstanceDef::Item(instance.def_id()),
args: instance.args,
}))
}
trace!("{:?}", this.dump_place(&dest.clone().into()));
this.go_to_block(ret);
Ok(None)
} }
/// Emulates a Miri-supported intrinsic (not supported by the core engine). /// Emulates a Miri-supported intrinsic (not supported by the core engine).
@ -92,7 +79,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
generic_args: ty::GenericArgsRef<'tcx>, generic_args: ty::GenericArgsRef<'tcx>,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, bool> { ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
if let Some(name) = intrinsic_name.strip_prefix("atomic_") { if let Some(name) = intrinsic_name.strip_prefix("atomic_") {
@ -103,6 +91,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
match intrinsic_name { match intrinsic_name {
"abort" => {
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
));
}
"catch_unwind" => {
this.handle_catch_unwind(args, dest, ret)?;
// THis pushed a stack frame, don't jump to `ret`.
return Ok(EmulateItemResult::AlreadyJumped);
}
// Raw memory accesses // Raw memory accesses
"volatile_load" => { "volatile_load" => {
let [place] = check_arg_count(args)?; let [place] = check_arg_count(args)?;
@ -426,9 +425,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap"))) throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap")))
} }
_ => return Ok(false), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(true) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
generic_args: ty::GenericArgsRef<'tcx>, generic_args: ty::GenericArgsRef<'tcx>,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, bool> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
match intrinsic_name { match intrinsic_name {
#[rustfmt::skip] #[rustfmt::skip]
@ -744,9 +744,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
} }
_ => return Ok(false), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(true) Ok(EmulateItemResult::NeedsJumping)
} }
fn fminmax_op( fn fminmax_op(

View File

@ -16,3 +16,13 @@ pub mod os_str;
pub mod panic; pub mod panic;
pub mod time; pub mod time;
pub mod tls; pub mod tls;
/// What needs to be done after emulating an item (a shim or an intrinsic) is done.
pub enum EmulateItemResult {
/// The caller is expected to jump to the return block.
NeedsJumping,
/// Jumping has already been taken care of.
AlreadyJumped,
/// The item is not supported.
NotSupported,
}

View File

@ -30,7 +30,7 @@ pub struct CatchUnwindData<'tcx> {
/// The return place from the original call to `try`. /// The return place from the original call to `try`.
dest: MPlaceTy<'tcx, Provenance>, dest: MPlaceTy<'tcx, Provenance>,
/// The return block from the original call to `try`. /// The return block from the original call to `try`.
ret: mir::BasicBlock, ret: Option<mir::BasicBlock>,
} }
impl VisitProvenance for CatchUnwindData<'_> { impl VisitProvenance for CatchUnwindData<'_> {
@ -73,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
&mut self, &mut self,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
ret: mir::BasicBlock, ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
@ -103,7 +103,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
&[data.into()], &[data.into()],
None, None,
// Directly return to caller. // Directly return to caller.
StackPopCleanup::Goto { ret: Some(ret), unwind: mir::UnwindAction::Continue }, StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Continue },
)?; )?;
// We ourselves will return `0`, eventually (will be overwritten if we catch a panic). // We ourselves will return `0`, eventually (will be overwritten if we catch a panic).
@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
None, None,
// Directly return to caller of `try`. // Directly return to caller of `try`.
StackPopCleanup::Goto { StackPopCleanup::Goto {
ret: Some(catch_unwind.ret), ret: catch_unwind.ret,
unwind: mir::UnwindAction::Continue, unwind: mir::UnwindAction::Continue,
}, },
)?; )?;

View File

@ -9,7 +9,6 @@ use rustc_target::spec::abi::Abi;
use crate::shims::alloc::EvalContextExt as _; use crate::shims::alloc::EvalContextExt as _;
use crate::shims::unix::*; use crate::shims::unix::*;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::freebsd::foreign_items as freebsd; use shims::unix::freebsd::foreign_items as freebsd;
use shims::unix::linux::foreign_items as linux; use shims::unix::linux::foreign_items as linux;
@ -43,7 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
@ -750,11 +749,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
_ => Ok(EmulateForeignItemResult::NotSupported), _ => Ok(EmulateItemResult::NotSupported),
}; };
} }
}; };
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -3,7 +3,6 @@ use rustc_target::spec::abi::Abi;
use crate::shims::unix::*; use crate::shims::unix::*;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
pub fn is_dyn_sym(_name: &str) -> bool { pub fn is_dyn_sym(_name: &str) -> bool {
false false
@ -17,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
match link_name.as_str() { match link_name.as_str() {
// Threading // Threading
@ -97,8 +96,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -5,7 +5,6 @@ use crate::machine::SIGRTMAX;
use crate::machine::SIGRTMIN; use crate::machine::SIGRTMIN;
use crate::shims::unix::*; use crate::shims::unix::*;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::linux::epoll::EvalContextExt as _; use shims::unix::linux::epoll::EvalContextExt as _;
use shims::unix::linux::eventfd::EvalContextExt as _; use shims::unix::linux::eventfd::EvalContextExt as _;
use shims::unix::linux::mem::EvalContextExt as _; use shims::unix::linux::mem::EvalContextExt as _;
@ -23,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
@ -156,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
id => { id => {
this.handle_unsupported(format!("can't execute syscall with ID {id}"))?; this.handle_unsupported(format!("can't execute syscall with ID {id}"))?;
return Ok(EmulateForeignItemResult::AlreadyJumped); return Ok(EmulateItemResult::AlreadyJumped);
} }
} }
} }
@ -204,10 +203,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_null(dest)?; this.write_null(dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
}; };
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -3,7 +3,6 @@ use rustc_target::spec::abi::Abi;
use crate::shims::unix::*; use crate::shims::unix::*;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
pub fn is_dyn_sym(_name: &str) -> bool { pub fn is_dyn_sym(_name: &str) -> bool {
false false
@ -17,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
@ -175,9 +174,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(res, dest)?; this.write_scalar(res, dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
}; };
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -12,7 +12,6 @@ use crate::shims::alloc::EvalContextExt as _;
use crate::shims::os_str::bytes_to_os_str; use crate::shims::os_str::bytes_to_os_str;
use crate::shims::windows::*; use crate::shims::windows::*;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
use shims::windows::handle::{Handle, PseudoHandle}; use shims::windows::handle::{Handle, PseudoHandle};
fn is_dyn_sym(name: &str) -> bool { fn is_dyn_sym(name: &str) -> bool {
@ -86,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
@ -721,9 +720,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_null(dest)?; this.write_null(dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -4,7 +4,6 @@ use rustc_span::Symbol;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -16,7 +15,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "aes")?; this.expect_target_feature_for_intrinsic(link_name, "aes")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -126,9 +125,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
} }
// TODO: Implement the `llvm.x86.aesni.aeskeygenassist` when possible // TODO: Implement the `llvm.x86.aesni.aeskeygenassist` when possible
// with an external crate. // with an external crate.
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -11,7 +11,6 @@ use super::{
FloatBinOp, FloatUnaryOp, FloatBinOp, FloatUnaryOp,
}; };
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -23,7 +22,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "avx")?; this.expect_target_feature_for_intrinsic(link_name, "avx")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -343,8 +342,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.write_scalar(Scalar::from_i32(res.into()), dest)?; this.write_scalar(Scalar::from_i32(res.into()), dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -9,7 +9,6 @@ use super::{
packuswb, pmulhrsw, psign, shift_simd_by_scalar, shift_simd_by_simd, ShiftOp, packuswb, pmulhrsw, psign, shift_simd_by_scalar, shift_simd_by_simd, ShiftOp,
}; };
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -21,7 +20,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "avx2")?; this.expect_target_feature_for_intrinsic(link_name, "avx2")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -437,8 +436,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
shift_simd_by_simd(this, left, right, which, dest)?; shift_simd_by_simd(this, left, right, which, dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -10,7 +10,6 @@ use rustc_target::spec::abi::Abi;
use crate::*; use crate::*;
use helpers::bool_to_simd_element; use helpers::bool_to_simd_element;
use shims::foreign_items::EmulateForeignItemResult;
mod aesni; mod aesni;
mod avx; mod avx;
@ -31,7 +30,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
// Prefix should have already been checked. // Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap();
@ -43,7 +42,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
// 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/addcarry-u32-addcarry-u64.html
"addcarry.32" | "addcarry.64" => { "addcarry.32" | "addcarry.64" => {
if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" { if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" {
return Ok(EmulateForeignItemResult::NotSupported); return Ok(EmulateItemResult::NotSupported);
} }
let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
@ -69,7 +68,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
// https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
"subborrow.32" | "subborrow.64" => { "subborrow.32" | "subborrow.64" => {
if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" { if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" {
return Ok(EmulateForeignItemResult::NotSupported); return Ok(EmulateItemResult::NotSupported);
} }
let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
@ -143,9 +142,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
); );
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -8,7 +8,6 @@ use super::{
FloatUnaryOp, FloatUnaryOp,
}; };
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -20,7 +19,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse")?; this.expect_target_feature_for_intrinsic(link_name, "sse")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -211,8 +210,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
} }
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -7,7 +7,6 @@ use super::{
packuswb, shift_simd_by_scalar, FloatBinOp, ShiftOp, packuswb, shift_simd_by_scalar, FloatBinOp, ShiftOp,
}; };
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -19,7 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse2")?; this.expect_target_feature_for_intrinsic(link_name, "sse2")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -387,8 +386,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
} }
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -4,7 +4,6 @@ use rustc_target::spec::abi::Abi;
use super::horizontal_bin_op; use super::horizontal_bin_op;
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -16,7 +15,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse3")?; this.expect_target_feature_for_intrinsic(link_name, "sse3")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -50,8 +49,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.mem_copy(src_ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; this.mem_copy(src_ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -3,7 +3,6 @@ use rustc_target::spec::abi::Abi;
use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked}; use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked};
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -15,7 +14,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse4.1")?; this.expect_target_feature_for_intrinsic(link_name, "sse4.1")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -175,8 +174,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.write_scalar(Scalar::from_i32(res.into()), dest)?; this.write_scalar(Scalar::from_i32(res.into()), dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }

View File

@ -4,7 +4,6 @@ use rustc_target::spec::abi::Abi;
use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use super::{horizontal_bin_op, int_abs, pmulhrsw, psign};
use crate::*; use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
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(super) trait EvalContextExt<'mir, 'tcx: 'mir>: pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
@ -16,7 +15,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
abi: Abi, abi: Abi,
args: &[OpTy<'tcx, Provenance>], args: &[OpTy<'tcx, Provenance>],
dest: &MPlaceTy<'tcx, Provenance>, dest: &MPlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> { ) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "ssse3")?; this.expect_target_feature_for_intrinsic(link_name, "ssse3")?;
// Prefix should have already been checked. // Prefix should have already been checked.
@ -136,8 +135,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
psign(this, left, right, dest)?; psign(this, left, right, dest)?;
} }
_ => return Ok(EmulateForeignItemResult::NotSupported), _ => return Ok(EmulateItemResult::NotSupported),
} }
Ok(EmulateForeignItemResult::NeedsJumping) Ok(EmulateItemResult::NeedsJumping)
} }
} }