Auto merge of #96946 - WaffleLapkin:ptr_mask, r=scottmcm · rust-lang/rust@1e978a3 (original) (raw)
File tree
10 files changed
lines changed
- rustc_codegen_cranelift/src/intrinsics
- rustc_codegen_gcc/src/intrinsic
- src/test/codegen/intrinsics
10 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -577,6 +577,13 @@ fn codegen_regular_intrinsic_call<'tcx>( | ||
577 | 577 | ret.write_cvalue(fx, CValue::by_val(res, base.layout())); |
578 | 578 | } |
579 | 579 | |
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 | + | |
580 | 587 | sym::transmute => { |
581 | 588 | intrinsic_args!(fx, args => (from); intrinsic); |
582 | 589 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -309,6 +309,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { | ||
309 | 309 | return; |
310 | 310 | } |
311 | 311 | |
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 | + | |
312 | 324 | _ if name_str.starts_with("simd_") => { |
313 | 325 | match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { |
314 | 326 | Ok(llval) => llval, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -886,6 +886,9 @@ impl<'ll> CodegenCx<'ll, '_> { | ||
886 | 886 | ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void); |
887 | 887 | ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void); |
888 | 888 | } |
889 | + | |
890 | +ifn!("llvm.ptrmask", fn(i8p, t_isize) -> i8p); | |
891 | + | |
889 | 892 | None |
890 | 893 | } |
891 | 894 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -71,6 +71,7 @@ fn get_simple_intrinsic<'ll>( | ||
71 | 71 | sym::nearbyintf64 => "llvm.nearbyint.f64", |
72 | 72 | sym::roundf32 => "llvm.round.f32", |
73 | 73 | sym::roundf64 => "llvm.round.f64", |
74 | + sym::ptr_mask => "llvm.ptrmask", | |
74 | 75 | _ => return None, |
75 | 76 | }; |
76 | 77 | Some(cx.get_intrinsic(llvm_name)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1114,6 +1114,7 @@ symbols! { | ||
1114 | 1114 | ptr, |
1115 | 1115 | ptr_guaranteed_eq, |
1116 | 1116 | ptr_guaranteed_ne, |
1117 | + ptr_mask, | |
1117 | 1118 | ptr_null, |
1118 | 1119 | ptr_null_mut, |
1119 | 1120 | ptr_offset_from, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -105,7 +105,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { | ||
105 | 105 | | sym::type_name |
106 | 106 | | sym::forget |
107 | 107 | | sym::black_box |
108 | - | sym::variant_count => hir::Unsafety::Normal, | |
108 | + | sym::variant_count | |
109 | + | sym::ptr_mask => hir::Unsafety::Normal, | |
109 | 110 | _ => hir::Unsafety::Unsafe, |
110 | 111 | } |
111 | 112 | } |
@@ -203,6 +204,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | ||
203 | 204 | ], |
204 | 205 | tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), |
205 | 206 | ), |
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 | + | |
206 | 216 | sym::copy | sym::copy_nonoverlapping => ( |
207 | 217 | 1, |
208 | 218 | vec![ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1287,6 +1287,17 @@ extern "rust-intrinsic" { | ||
1287 | 1287 | #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] |
1288 | 1288 | pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T; |
1289 | 1289 | |
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 | + | |
1290 | 1301 | /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with |
1291 | 1302 | /// a size of `count` * `size_of::()` and an alignment of |
1292 | 1303 | /// `min_align_of::()` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -559,6 +559,21 @@ impl<T: ?Sized> *const T { | ||
559 | 559 | from_raw_parts::<T>(self.cast::<u8>().wrapping_offset(count).cast::<()>(), metadata(self)) |
560 | 560 | } |
561 | 561 | |
562 | +/// Masks out bits of the pointer according to a mask. | |
563 | + /// | |
564 | + /// This is convenience for `ptr.map_addr(|a | |
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 | + | |
562 | 577 | /// Calculates the distance between two pointers. The returned value is in |
563 | 578 | /// units of T: the distance in bytes divided by `mem::size_of::()`. |
564 | 579 | /// |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -575,6 +575,21 @@ impl<T: ?Sized> *mut T { | ||
575 | 575 | ) |
576 | 576 | } |
577 | 577 | |
578 | +/// Masks out bits of the pointer according to a mask. | |
579 | + /// | |
580 | + /// This is convenience for `ptr.map_addr(|a | |
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 | + | |
578 | 593 | /// Returns `None` if the pointer is null, or else returns a unique reference to |
579 | 594 | /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`] |
580 | 595 | /// must be used instead. |
Original file line number | Diff line number | Diff 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 | |
10 | + core::intrinsics::ptr_mask(ptr, mask) | |
11 | +} |