Auto merge of #101483 - oli-obk:guaranteed_opt, r=fee1-dead
The `<*const T>::guaranteed_*` methods now return an option for the unknown case cc https://github.com/rust-lang/rust/issues/53020#issuecomment-1236932443 I chose `0` for "not equal" and `1` for "equal" and left `2` for the unknown case so backends can just forward to raw pointer equality and it works ✨ r? `@fee1-dead` or `@lcnr` cc `@rust-lang/wg-const-eval`
This commit is contained in:
commit
5197c96c49
12 changed files with 119 additions and 138 deletions
|
@ -816,20 +816,13 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
ret.write_cvalue(fx, val);
|
||||
}
|
||||
|
||||
sym::ptr_guaranteed_eq => {
|
||||
sym::ptr_guaranteed_cmp => {
|
||||
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||
|
||||
let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
|
||||
ret.write_cvalue(fx, val);
|
||||
}
|
||||
|
||||
sym::ptr_guaranteed_ne => {
|
||||
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||
|
||||
let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
|
||||
ret.write_cvalue(fx, val);
|
||||
}
|
||||
|
||||
sym::caller_location => {
|
||||
intrinsic_args!(fx, args => (); intrinsic);
|
||||
|
||||
|
|
|
@ -551,14 +551,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
return;
|
||||
}
|
||||
|
||||
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
||||
sym::ptr_guaranteed_cmp => {
|
||||
let a = args[0].immediate();
|
||||
let b = args[1].immediate();
|
||||
if name == sym::ptr_guaranteed_eq {
|
||||
bx.icmp(IntPredicate::IntEQ, a, b)
|
||||
} else {
|
||||
bx.icmp(IntPredicate::IntNE, a, b)
|
||||
}
|
||||
bx.icmp(IntPredicate::IntEQ, a, b)
|
||||
}
|
||||
|
||||
sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
|
||||
|
|
|
@ -191,34 +191,35 @@ impl interpret::MayLeak for ! {
|
|||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
|
||||
/// See documentation on the `ptr_guaranteed_cmp` intrinsic.
|
||||
fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
|
||||
Ok(match (a, b) {
|
||||
// Comparisons between integers are always known.
|
||||
(Scalar::Int { .. }, Scalar::Int { .. }) => a == b,
|
||||
// Equality with integers can never be known for sure.
|
||||
(Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 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) -> InterpResult<'tcx, bool> {
|
||||
Ok(match (a, b) {
|
||||
// Comparisons between integers are always known.
|
||||
(Scalar::Int(_), Scalar::Int(_)) => a != b,
|
||||
(Scalar::Int { .. }, Scalar::Int { .. }) => {
|
||||
if a == b {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
// Inequality with integers other than null can never be known for sure.
|
||||
(Scalar::Int(int), ptr @ Scalar::Ptr(..))
|
||||
| (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => {
|
||||
int.is_null() && !self.scalar_may_be_null(ptr)?
|
||||
| (ptr @ Scalar::Ptr(..), Scalar::Int(int))
|
||||
if int.is_null() && !self.scalar_may_be_null(ptr)? =>
|
||||
{
|
||||
0
|
||||
}
|
||||
// FIXME: return `true` for at least some comparisons where we can reliably
|
||||
// Equality with integers can never be known for sure.
|
||||
(Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2,
|
||||
// FIXME: return a `1` 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).
|
||||
// FIXME: return `0` 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,
|
||||
(Scalar::Ptr(..), Scalar::Ptr(..)) => 2,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -329,15 +330,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
|
||||
};
|
||||
match intrinsic_name {
|
||||
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
||||
sym::ptr_guaranteed_cmp => {
|
||||
let a = ecx.read_scalar(&args[0])?;
|
||||
let b = ecx.read_scalar(&args[1])?;
|
||||
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)?;
|
||||
let cmp = ecx.guaranteed_cmp(a, b)?;
|
||||
ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
|
||||
}
|
||||
sym::const_allocate => {
|
||||
let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
|
||||
|
|
|
@ -97,7 +97,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
}
|
||||
|
||||
// Raw pointers are not allowed in type level constants, as we cannot properly test them for
|
||||
// equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
|
||||
// equality at compile-time (see `ptr_guaranteed_cmp`).
|
||||
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
|
||||
// agree with runtime equality tests.
|
||||
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
|
||||
|
|
|
@ -1117,8 +1117,7 @@ symbols! {
|
|||
profiler_builtins,
|
||||
profiler_runtime,
|
||||
ptr,
|
||||
ptr_guaranteed_eq,
|
||||
ptr_guaranteed_ne,
|
||||
ptr_guaranteed_cmp,
|
||||
ptr_mask,
|
||||
ptr_null,
|
||||
ptr_null_mut,
|
||||
|
|
|
@ -95,8 +95,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
|
|||
| sym::type_id
|
||||
| sym::likely
|
||||
| sym::unlikely
|
||||
| sym::ptr_guaranteed_eq
|
||||
| sym::ptr_guaranteed_ne
|
||||
| sym::ptr_guaranteed_cmp
|
||||
| sym::minnumf32
|
||||
| sym::minnumf64
|
||||
| sym::maxnumf32
|
||||
|
@ -302,8 +301,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
|
|||
(1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
|
||||
}
|
||||
|
||||
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
||||
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
|
||||
sym::ptr_guaranteed_cmp => {
|
||||
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8)
|
||||
}
|
||||
|
||||
sym::const_allocate => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue