Skip to content

Commit 940f078

Browse files
committed
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*
1 parent 9bbbf60 commit 940f078

File tree

8 files changed

+65
-1
lines changed

8 files changed

+65
-1
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,13 @@ fn codegen_regular_intrinsic_call<'tcx>(
540540
ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
541541
}
542542

543+
sym::ptr_mask => {
544+
intrinsic_args!(fx, args => (ptr, mask); intrinsic);
545+
let ptr_val = ptr.load_scalar(fx);
546+
547+
fx.bcx.ins().band(ptr_val, mask);
548+
}
549+
543550
sym::transmute => {
544551
intrinsic_args!(fx, args => (from); intrinsic);
545552

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ impl<'ll> CodegenCx<'ll, '_> {
655655

656656
let i8p = self.type_i8p();
657657
let void = self.type_void();
658+
let voidp = self.type_ptr_to(void);
658659
let i1 = self.type_i1();
659660
let t_i8 = self.type_i8();
660661
let t_i16 = self.type_i16();
@@ -897,6 +898,9 @@ impl<'ll> CodegenCx<'ll, '_> {
897898
ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void);
898899
ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void);
899900
}
901+
902+
ifn!("llvm.ptrmask", fn(voidp, t_isize) -> voidp);
903+
900904
None
901905
}
902906

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ fn get_simple_intrinsic<'ll>(
7171
sym::nearbyintf64 => "llvm.nearbyint.f64",
7272
sym::roundf32 => "llvm.round.f32",
7373
sym::roundf64 => "llvm.round.f64",
74+
sym::ptr_mask => "llvm.ptrmask",
7475
_ => return None,
7576
};
7677
Some(cx.get_intrinsic(llvm_name))

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,7 @@ symbols! {
11121112
ptr,
11131113
ptr_guaranteed_eq,
11141114
ptr_guaranteed_ne,
1115+
ptr_mask,
11151116
ptr_null,
11161117
ptr_null_mut,
11171118
ptr_offset_from,

compiler/rustc_typeck/src/check/intrinsic.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
102102
| sym::type_name
103103
| sym::forget
104104
| sym::black_box
105-
| sym::variant_count => hir::Unsafety::Normal,
105+
| sym::variant_count
106+
| sym::ptr_mask => hir::Unsafety::Normal,
106107
_ => hir::Unsafety::Unsafe,
107108
}
108109
}
@@ -200,6 +201,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
200201
],
201202
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
202203
),
204+
sym::ptr_mask => (
205+
1,
206+
vec![
207+
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
208+
tcx.types.usize,
209+
],
210+
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
211+
),
212+
203213
sym::copy | sym::copy_nonoverlapping => (
204214
1,
205215
vec![

library/core/src/intrinsics.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,17 @@ extern "rust-intrinsic" {
15181518
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
15191519
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
15201520

1521+
/// Masks out bits of the pointer according to a mask.
1522+
///
1523+
/// Note that, unlike most intrinsics, this is safe to call;
1524+
/// it does not require an `unsafe` block.
1525+
/// Therefore, implementations must not require the user to uphold
1526+
/// any safety invariants.
1527+
///
1528+
/// Consider using [`pointer::mask`] instead.
1529+
#[cfg(not(bootstrap))]
1530+
pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
1531+
15211532
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
15221533
/// a size of `count` * `size_of::<T>()` and an alignment of
15231534
/// `min_align_of::<T>()`

library/core/src/ptr/const_ptr.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,21 @@ impl<T: ?Sized> *const T {
559559
from_raw_parts::<T>(self.cast::<u8>().wrapping_offset(count).cast::<()>(), metadata(self))
560560
}
561561

562+
/// Masks out bits of the pointer according to a mask.
563+
///
564+
/// This is convenience for `ptr.map_addr(|a| a & mask)`.
565+
///
566+
/// For non-`Sized` pointees this operation changes only the data pointer,
567+
/// leaving the metadata untouched.
568+
#[cfg(not(bootstrap))]
569+
#[unstable(feature = "ptr_mask", issue = "none")]
570+
#[must_use = "returns a new pointer rather than modifying its argument"]
571+
#[inline(always)]
572+
pub fn mask(self, mask: usize) -> *const T {
573+
let this = intrinsics::ptr_mask(self.cast::<()>(), mask);
574+
from_raw_parts::<T>(this, metadata(self))
575+
}
576+
562577
/// Calculates the distance between two pointers. The returned value is in
563578
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
564579
///

library/core/src/ptr/mut_ptr.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,21 @@ impl<T: ?Sized> *mut T {
575575
)
576576
}
577577

578+
/// Masks out bits of the pointer according to a mask.
579+
///
580+
/// This is convenience for `ptr.map_addr(|a| a & mask)`.
581+
///
582+
/// For non-`Sized` pointees this operation changes only the data pointer,
583+
/// leaving the metadata untouched.
584+
#[cfg(not(bootstrap))]
585+
#[unstable(feature = "ptr_mask", issue = "none")]
586+
#[must_use = "returns a new pointer rather than modifying its argument"]
587+
#[inline(always)]
588+
pub fn mask(self, mask: usize) -> *mut T {
589+
let this = intrinsics::ptr_mask(self.cast::<()>(), mask) as *mut ();
590+
from_raw_parts_mut::<T>(this, metadata(self))
591+
}
592+
578593
/// Returns `None` if the pointer is null, or else returns a unique reference to
579594
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`]
580595
/// must be used instead.

0 commit comments

Comments
 (0)