Skip to content

Commit 7bdb5de

Browse files
committed
Auto merge of rust-lang#76634 - RalfJung:miri-guaranteed-eq-ne, r=oli-obk
move guaranteed{ne,eq} implementation to compile-time machine Currently, Miri needs a special hack to avoid using the core engine implementation of these intrinsics. That seems silly, so let's move them to the CTFE machine, which is the only machine that wants to use them. I also added a reference to rust-lang#73722 as a warning to anyone who wants to adjust `guaranteed_eq`.
2 parents 95386b6 + c321276 commit 7bdb5de

File tree

2 files changed

+70
-44
lines changed

2 files changed

+70
-44
lines changed

compiler/rustc_mir/src/const_eval/machine.rs

+68-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_ast::Mutability;
1111
use rustc_hir::def_id::DefId;
1212
use rustc_middle::mir::AssertMessage;
1313
use rustc_session::Limit;
14-
use rustc_span::symbol::Symbol;
14+
use rustc_span::symbol::{sym, Symbol};
1515

1616
use crate::interpret::{
1717
self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx,
@@ -176,6 +176,38 @@ impl interpret::MayLeak for ! {
176176
}
177177
}
178178

179+
impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
180+
fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool {
181+
match (a, b) {
182+
// Comparisons between integers are always known.
183+
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b,
184+
// Equality with integers can never be known for sure.
185+
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
186+
// FIXME: return `true` for when both sides are the same pointer, *except* that
187+
// some things (like functions and vtables) do not have stable addresses
188+
// so we need to be careful around them (see e.g. #73722).
189+
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
190+
}
191+
}
192+
193+
fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool {
194+
match (a, b) {
195+
// Comparisons between integers are always known.
196+
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b,
197+
// Comparisons of abstract pointers with null pointers are known if the pointer
198+
// is in bounds, because if they are in bounds, the pointer can't be null.
199+
(Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr))
200+
| (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr),
201+
// Inequality with integers other than null can never be known for sure.
202+
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
203+
// FIXME: return `true` for at least some comparisons where we can reliably
204+
// determine the result of runtime inequality tests at compile-time.
205+
// Examples include comparison of addresses in different static items.
206+
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
207+
}
208+
}
209+
}
210+
179211
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
180212
compile_time_machine!(<'mir, 'tcx>);
181213

@@ -234,12 +266,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
234266
ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
235267
_unwind: Option<mir::BasicBlock>,
236268
) -> InterpResult<'tcx> {
269+
// Shared intrinsics.
237270
if ecx.emulate_intrinsic(instance, args, ret)? {
238271
return Ok(());
239272
}
240-
// An intrinsic that we do not support
241273
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
242-
Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into())
274+
275+
// CTFE-specific intrinsics.
276+
let (dest, ret) = match ret {
277+
None => {
278+
return Err(ConstEvalErrKind::NeedsRfc(format!(
279+
"calling intrinsic `{}`",
280+
intrinsic_name
281+
))
282+
.into());
283+
}
284+
Some(p) => p,
285+
};
286+
match intrinsic_name {
287+
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
288+
let a = ecx.read_immediate(args[0])?.to_scalar()?;
289+
let b = ecx.read_immediate(args[1])?.to_scalar()?;
290+
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
291+
ecx.guaranteed_eq(a, b)
292+
} else {
293+
ecx.guaranteed_ne(a, b)
294+
};
295+
ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
296+
}
297+
_ => {
298+
return Err(ConstEvalErrKind::NeedsRfc(format!(
299+
"calling intrinsic `{}`",
300+
intrinsic_name
301+
))
302+
.into());
303+
}
304+
}
305+
306+
ecx.go_to_block(ret);
307+
Ok(())
243308
}
244309

245310
fn assert_panic(

compiler/rustc_mir/src/interpret/intrinsics.rs

+2-41
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ crate fn eval_nullary_intrinsic<'tcx>(
8888

8989
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9090
/// Returns `true` if emulation happened.
91+
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
92+
/// intrinsic handling.
9193
pub fn emulate_intrinsic(
9294
&mut self,
9395
instance: ty::Instance<'tcx>,
@@ -328,16 +330,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
328330
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
329331
self.write_scalar(offset_ptr, dest)?;
330332
}
331-
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
332-
let a = self.read_immediate(args[0])?.to_scalar()?;
333-
let b = self.read_immediate(args[1])?.to_scalar()?;
334-
let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
335-
self.guaranteed_eq(a, b)
336-
} else {
337-
self.guaranteed_ne(a, b)
338-
};
339-
self.write_scalar(Scalar::from_bool(cmp), dest)?;
340-
}
341333
sym::ptr_offset_from => {
342334
let a = self.read_immediate(args[0])?.to_scalar()?;
343335
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> {
448440
Ok(true)
449441
}
450442

451-
fn guaranteed_eq(&mut self, a: Scalar<M::PointerTag>, b: Scalar<M::PointerTag>) -> bool {
452-
match (a, b) {
453-
// Comparisons between integers are always known.
454-
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b,
455-
// Equality with integers can never be known for sure.
456-
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
457-
// FIXME: return `true` for when both sides are the same pointer, *except* that
458-
// some things (like functions and vtables) do not have stable addresses
459-
// so we need to be careful around them.
460-
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
461-
}
462-
}
463-
464-
fn guaranteed_ne(&mut self, a: Scalar<M::PointerTag>, b: Scalar<M::PointerTag>) -> bool {
465-
match (a, b) {
466-
// Comparisons between integers are always known.
467-
(Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b,
468-
// Comparisons of abstract pointers with null pointers are known if the pointer
469-
// is in bounds, because if they are in bounds, the pointer can't be null.
470-
(Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr))
471-
| (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr),
472-
// Inequality with integers other than null can never be known for sure.
473-
(Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false,
474-
// FIXME: return `true` for at least some comparisons where we can reliably
475-
// determine the result of runtime inequality tests at compile-time.
476-
// Examples include comparison of addresses in static items, for these we can
477-
// give reliable results.
478-
(Scalar::Ptr(_), Scalar::Ptr(_)) => false,
479-
}
480-
}
481-
482443
pub fn exact_div(
483444
&mut self,
484445
a: ImmTy<'tcx, M::PointerTag>,

0 commit comments

Comments
 (0)