Skip to content

Commit c321276

Browse files
committed
move guaranteed{ne,eq} implementation to compile-time machine
1 parent 0f5c769 commit c321276

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)