From 10270f4b442207b23b28f776b8dda297bd03570a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 11 May 2022 17:52:00 +0400 Subject: [PATCH] Add pointer masking convenience functions This commit adds the following functions all of which have a signature `pointer, usize -> pointer`: - `<*mut T>::mask` - `<*const T>::mask` - `intrinsics::ptr_mask` These functions are equivalent to `.map_addr(|a| a & mask)` but they utilize `llvm.ptrmask` llvm intrinsic. *masks your pointers* --- .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 7 +++++++ compiler/rustc_codegen_llvm/src/context.rs | 4 ++++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/intrinsic.rs | 12 +++++++++++- library/core/src/intrinsics.rs | 11 +++++++++++ library/core/src/ptr/const_ptr.rs | 15 +++++++++++++++ library/core/src/ptr/mut_ptr.rs | 15 +++++++++++++++ 8 files changed, 65 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index b2a83e1d4eb..65e964c786b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -540,6 +540,13 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(res, base.layout())); } + sym::ptr_mask => { + intrinsic_args!(fx, args => (ptr, mask); intrinsic); + let ptr_val = ptr.load_scalar(fx); + + fx.bcx.ins().band(ptr_val, mask); + } + sym::transmute => { intrinsic_args!(fx, args => (from); intrinsic); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d4d84147239..bbb6bacc452 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -644,6 +644,7 @@ impl<'ll> CodegenCx<'ll, '_> { let i8p = self.type_i8p(); let void = self.type_void(); + let voidp = self.type_ptr_to(void); let i1 = self.type_i1(); let t_i8 = self.type_i8(); let t_i16 = self.type_i16(); @@ -886,6 +887,9 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void); ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void); } + + ifn!("llvm.ptrmask", fn(voidp, t_isize) -> voidp); + None } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9f364749287..1a0e44fdc5b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -71,6 +71,7 @@ fn get_simple_intrinsic<'ll>( sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", + sym::ptr_mask => "llvm.ptrmask", _ => return None, }; Some(cx.get_intrinsic(llvm_name)) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 156f53ac486..19e136a4476 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1112,6 +1112,7 @@ symbols! { ptr, ptr_guaranteed_eq, ptr_guaranteed_ne, + ptr_mask, ptr_null, ptr_null_mut, ptr_offset_from, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 05686be5d4b..73dd7122e26 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -105,7 +105,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { | sym::type_name | sym::forget | sym::black_box - | sym::variant_count => hir::Unsafety::Normal, + | sym::variant_count + | sym::ptr_mask => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } } @@ -203,6 +204,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), + sym::ptr_mask => ( + 1, + vec![ + tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + tcx.types.usize, + ], + tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), + ), + sym::copy | sym::copy_nonoverlapping => ( 1, vec![ diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 15467e0191d..c95dae745f4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1308,6 +1308,17 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] pub fn arith_offset(dst: *const T, offset: isize) -> *const T; + /// Masks out bits of the pointer according to a mask. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// Consider using [`pointer::mask`] instead. + #[cfg(not(bootstrap))] + pub fn ptr_mask(ptr: *const T, mask: usize) -> *const T; + /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index c25b159c533..624d283155a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -559,6 +559,21 @@ impl *const T { from_raw_parts::(self.cast::().wrapping_offset(count).cast::<()>(), metadata(self)) } + /// Masks out bits of the pointer according to a mask. + /// + /// This is convenience for `ptr.map_addr(|a| a & mask)`. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[cfg(not(bootstrap))] + #[unstable(feature = "ptr_mask", issue = "none")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + pub fn mask(self, mask: usize) -> *const T { + let this = intrinsics::ptr_mask(self.cast::<()>(), mask); + from_raw_parts::(this, metadata(self)) + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::()`. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index fff06b458c7..ea87bb88a1b 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -575,6 +575,21 @@ impl *mut T { ) } + /// Masks out bits of the pointer according to a mask. + /// + /// This is convenience for `ptr.map_addr(|a| a & mask)`. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[cfg(not(bootstrap))] + #[unstable(feature = "ptr_mask", issue = "none")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + pub fn mask(self, mask: usize) -> *mut T { + let this = intrinsics::ptr_mask(self.cast::<()>(), mask) as *mut (); + from_raw_parts_mut::(this, metadata(self)) + } + /// Returns `None` if the pointer is null, or else returns a unique reference to /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`] /// must be used instead.