Skip to content

Commit 1e978a3

Browse files
committed
Auto merge of #96946 - WaffleLapkin:ptr_mask, r=scottmcm
Add pointer masking convenience functions This PR adds the following public API: ```rust impl<T: ?Sized> *const T { fn mask(self, mask: usize) -> *const T; } impl<T: ?Sized> *mut T { fn mask(self, mask: usize) -> *const T; } // mod intrinsics fn mask<T>(ptr: *const T, mask: usize) -> *const T ``` This is equivalent to `ptr.map_addr(|a| a & mask)` but also uses a cool llvm intrinsic. Proposed in #95643 (comment) cc `@Gankra` `@scottmcm` `@RalfJung` r? rust-lang/libs-api
2 parents eaadb89 + ca75312 commit 1e978a3

File tree

10 files changed

+87
-1
lines changed

10 files changed

+87
-1
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,13 @@ fn codegen_regular_intrinsic_call<'tcx>(
577577
ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
578578
}
579579

580+
sym::ptr_mask => {
581+
intrinsic_args!(fx, args => (ptr, mask); intrinsic);
582+
let ptr = ptr.load_scalar(fx);
583+
let mask = mask.load_scalar(fx);
584+
fx.bcx.ins().band(ptr, mask);
585+
}
586+
580587
sym::transmute => {
581588
intrinsic_args!(fx, args => (from); intrinsic);
582589

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
309309
return;
310310
}
311311

312+
sym::ptr_mask => {
313+
let usize_type = self.context.new_type::<usize>();
314+
let void_ptr_type = self.context.new_type::<*const ()>();
315+
316+
let ptr = args[0].immediate();
317+
let mask = args[1].immediate();
318+
319+
let addr = self.bitcast(ptr, usize_type);
320+
let masked = self.and(addr, mask);
321+
self.bitcast(masked, void_ptr_type)
322+
},
323+
312324
_ if name_str.starts_with("simd_") => {
313325
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
314326
Ok(llval) => llval,

compiler/rustc_codegen_llvm/src/context.rs

+3
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,9 @@ impl<'ll> CodegenCx<'ll, '_> {
886886
ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void);
887887
ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void);
888888
}
889+
890+
ifn!("llvm.ptrmask", fn(i8p, t_isize) -> i8p);
891+
889892
None
890893
}
891894

compiler/rustc_codegen_llvm/src/intrinsic.rs

+1
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

+1
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ symbols! {
11141114
ptr,
11151115
ptr_guaranteed_eq,
11161116
ptr_guaranteed_ne,
1117+
ptr_mask,
11171118
ptr_null,
11181119
ptr_null_mut,
11191120
ptr_offset_from,

compiler/rustc_typeck/src/check/intrinsic.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
105105
| sym::type_name
106106
| sym::forget
107107
| sym::black_box
108-
| sym::variant_count => hir::Unsafety::Normal,
108+
| sym::variant_count
109+
| sym::ptr_mask => hir::Unsafety::Normal,
109110
_ => hir::Unsafety::Unsafe,
110111
}
111112
}
@@ -203,6 +204,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
203204
],
204205
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
205206
),
207+
sym::ptr_mask => (
208+
1,
209+
vec![
210+
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
211+
tcx.types.usize,
212+
],
213+
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
214+
),
215+
206216
sym::copy | sym::copy_nonoverlapping => (
207217
1,
208218
vec![

library/core/src/intrinsics.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,17 @@ extern "rust-intrinsic" {
12871287
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
12881288
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
12891289

1290+
/// Masks out bits of the pointer according to a mask.
1291+
///
1292+
/// Note that, unlike most intrinsics, this is safe to call;
1293+
/// it does not require an `unsafe` block.
1294+
/// Therefore, implementations must not require the user to uphold
1295+
/// any safety invariants.
1296+
///
1297+
/// Consider using [`pointer::mask`] instead.
1298+
#[cfg(not(bootstrap))]
1299+
pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
1300+
12901301
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
12911302
/// a size of `count` * `size_of::<T>()` and an alignment of
12921303
/// `min_align_of::<T>()`

library/core/src/ptr/const_ptr.rs

+15
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 = "98290")]
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

+15
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 = "98290")]
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.

src/test/codegen/intrinsics/mask.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![crate_type = "lib"]
2+
#![feature(core_intrinsics)]
3+
4+
// CHECK-LABEL: @mask_ptr
5+
// CHECK-SAME: [[WORD:i[0-9]+]] %mask
6+
#[no_mangle]
7+
pub fn mask_ptr(ptr: *const u16, mask: usize) -> *const u16 {
8+
// CHECK: call
9+
// CHECK-SAME: @llvm.ptrmask.{{p0|p0i8}}.[[WORD]]({{ptr|i8\*}} {{%ptr|%0}}, [[WORD]] %mask)
10+
core::intrinsics::ptr_mask(ptr, mask)
11+
}

0 commit comments

Comments
 (0)