move guaranteed{ne,eq} implementation to compile-time machine
This commit is contained in:
parent
0f5c769513
commit
c32127675a
2 changed files with 70 additions and 44 deletions
|
@ -11,7 +11,7 @@ use rustc_ast::Mutability;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::AssertMessage;
|
use rustc_middle::mir::AssertMessage;
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx,
|
self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx,
|
||||||
|
@ -176,6 +176,38 @@ impl interpret::MayLeak for ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||||
|
fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool {
|
||||||
|
match (a, b) {
|
||||||
|
// Comparisons between integers are always known.
|
||||||
|
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b,
|
||||||
|
// Equality with integers can never be known for sure.
|
||||||
|
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
|
||||||
|
// FIXME: return `true` for when both sides are the same pointer, *except* that
|
||||||
|
// some things (like functions and vtables) do not have stable addresses
|
||||||
|
// so we need to be careful around them (see e.g. #73722).
|
||||||
|
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool {
|
||||||
|
match (a, b) {
|
||||||
|
// Comparisons between integers are always known.
|
||||||
|
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b,
|
||||||
|
// Comparisons of abstract pointers with null pointers are known if the pointer
|
||||||
|
// is in bounds, because if they are in bounds, the pointer can't be null.
|
||||||
|
(Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr))
|
||||||
|
| (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr),
|
||||||
|
// Inequality with integers other than null can never be known for sure.
|
||||||
|
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
|
||||||
|
// FIXME: return `true` for at least some comparisons where we can reliably
|
||||||
|
// determine the result of runtime inequality tests at compile-time.
|
||||||
|
// Examples include comparison of addresses in different static items.
|
||||||
|
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
|
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
|
||||||
compile_time_machine!(<'mir, 'tcx>);
|
compile_time_machine!(<'mir, 'tcx>);
|
||||||
|
|
||||||
|
@ -234,12 +266,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
|
ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
|
||||||
_unwind: Option<mir::BasicBlock>,
|
_unwind: Option<mir::BasicBlock>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
|
// Shared intrinsics.
|
||||||
if ecx.emulate_intrinsic(instance, args, ret)? {
|
if ecx.emulate_intrinsic(instance, args, ret)? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// An intrinsic that we do not support
|
|
||||||
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
|
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
|
||||||
Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into())
|
|
||||||
|
// CTFE-specific intrinsics.
|
||||||
|
let (dest, ret) = match ret {
|
||||||
|
None => {
|
||||||
|
return Err(ConstEvalErrKind::NeedsRfc(format!(
|
||||||
|
"calling intrinsic `{}`",
|
||||||
|
intrinsic_name
|
||||||
|
))
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
Some(p) => p,
|
||||||
|
};
|
||||||
|
match intrinsic_name {
|
||||||
|
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
||||||
|
let a = ecx.read_immediate(args[0])?.to_scalar()?;
|
||||||
|
let b = ecx.read_immediate(args[1])?.to_scalar()?;
|
||||||
|
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
|
||||||
|
ecx.guaranteed_eq(a, b)
|
||||||
|
} else {
|
||||||
|
ecx.guaranteed_ne(a, b)
|
||||||
|
};
|
||||||
|
ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ConstEvalErrKind::NeedsRfc(format!(
|
||||||
|
"calling intrinsic `{}`",
|
||||||
|
intrinsic_name
|
||||||
|
))
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ecx.go_to_block(ret);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
|
|
|
@ -88,6 +88,8 @@ crate fn eval_nullary_intrinsic<'tcx>(
|
||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
/// Returns `true` if emulation happened.
|
/// Returns `true` if emulation happened.
|
||||||
|
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
|
||||||
|
/// intrinsic handling.
|
||||||
pub fn emulate_intrinsic(
|
pub fn emulate_intrinsic(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
|
@ -328,16 +330,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
|
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
|
||||||
self.write_scalar(offset_ptr, dest)?;
|
self.write_scalar(offset_ptr, dest)?;
|
||||||
}
|
}
|
||||||
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
|
||||||
let a = self.read_immediate(args[0])?.to_scalar()?;
|
|
||||||
let b = self.read_immediate(args[1])?.to_scalar()?;
|
|
||||||
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
|
|
||||||
self.guaranteed_eq(a, b)
|
|
||||||
} else {
|
|
||||||
self.guaranteed_ne(a, b)
|
|
||||||
};
|
|
||||||
self.write_scalar(Scalar::from_bool(cmp), dest)?;
|
|
||||||
}
|
|
||||||
sym::ptr_offset_from => {
|
sym::ptr_offset_from => {
|
||||||
let a = self.read_immediate(args[0])?.to_scalar()?;
|
let a = self.read_immediate(args[0])?.to_scalar()?;
|
||||||
let b = self.read_immediate(args[1])?.to_scalar()?;
|
let b = self.read_immediate(args[1])?.to_scalar()?;
|
||||||
|
@ -448,37 +440,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guaranteed_eq(&mut self, a: Scalar<M::PointerTag>, b: Scalar<M::PointerTag>) -> bool {
|
|
||||||
match (a, b) {
|
|
||||||
// Comparisons between integers are always known.
|
|
||||||
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b,
|
|
||||||
// Equality with integers can never be known for sure.
|
|
||||||
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
|
|
||||||
// FIXME: return `true` for when both sides are the same pointer, *except* that
|
|
||||||
// some things (like functions and vtables) do not have stable addresses
|
|
||||||
// so we need to be careful around them.
|
|
||||||
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn guaranteed_ne(&mut self, a: Scalar<M::PointerTag>, b: Scalar<M::PointerTag>) -> bool {
|
|
||||||
match (a, b) {
|
|
||||||
// Comparisons between integers are always known.
|
|
||||||
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b,
|
|
||||||
// Comparisons of abstract pointers with null pointers are known if the pointer
|
|
||||||
// is in bounds, because if they are in bounds, the pointer can't be null.
|
|
||||||
(Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr))
|
|
||||||
| (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr),
|
|
||||||
// Inequality with integers other than null can never be known for sure.
|
|
||||||
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
|
|
||||||
// FIXME: return `true` for at least some comparisons where we can reliably
|
|
||||||
// determine the result of runtime inequality tests at compile-time.
|
|
||||||
// Examples include comparison of addresses in static items, for these we can
|
|
||||||
// give reliable results.
|
|
||||||
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exact_div(
|
pub fn exact_div(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: ImmTy<'tcx, M::PointerTag>,
|
a: ImmTy<'tcx, M::PointerTag>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue