Skip to content

Commit 6d5bf8b

Browse files
committed
Remove the intrinsic for align_offset
Keep only the language item. This removes some indirection and makes codegen worse for debug builds, but simplifies code significantly, which is a good tradeoff to make, in my opinion. Besides, the codegen can be improved even further with some constant evaluation improvements that we expect to happen in the future.
1 parent 680031b commit 6d5bf8b

File tree

5 files changed

+26
-84
lines changed

5 files changed

+26
-84
lines changed

src/libcore/intrinsics.rs

-42
Original file line numberDiff line numberDiff line change
@@ -1467,48 +1467,6 @@ extern "rust-intrinsic" {
14671467
/// docs my friends, its friday!
14681468
pub fn align_offset(ptr: *const (), align: usize) -> usize;
14691469

1470-
/// Computes the offset that needs to be applied to the pointer in order to make it aligned to
1471-
/// `align`.
1472-
///
1473-
/// If it is not possible to align the pointer, the implementation returns
1474-
/// `usize::max_value()`.
1475-
///
1476-
/// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
1477-
/// used with the `offset` or `offset_to` methods.
1478-
///
1479-
/// There are no guarantees whatsover that offsetting the pointer will not overflow or go
1480-
/// beyond the allocation that the pointer points into. It is up to the caller to ensure that
1481-
/// the returned offset is correct in all terms other than alignment.
1482-
///
1483-
/// # Unsafety
1484-
///
1485-
/// `align` must be a power-of-two.
1486-
///
1487-
/// # Examples
1488-
///
1489-
/// Accessing adjacent `u8` as `u16`
1490-
///
1491-
/// ```
1492-
/// # #![feature(core_intrinsics)]
1493-
/// # fn foo(n: usize) {
1494-
/// # use std::intrinsics::align_offset;
1495-
/// # use std::mem::align_of;
1496-
/// # unsafe {
1497-
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
1498-
/// let ptr = &x[n] as *const u8;
1499-
/// let offset = align_offset(ptr, align_of::<u16>());
1500-
/// if offset < x.len() - n - 1 {
1501-
/// let u16_ptr = ptr.offset(offset as isize) as *const u16;
1502-
/// assert_ne!(*u16_ptr, 500);
1503-
/// } else {
1504-
/// // while the pointer can be aligned via `offset`, it would point
1505-
/// // outside the allocation
1506-
/// }
1507-
/// # } }
1508-
/// ```
1509-
#[cfg(not(stage0))]
1510-
pub fn align_offset<T>(ptr: *const T, align: usize) -> usize;
1511-
15121470
/// Emits a `!nontemporal` store according to LLVM (see their docs).
15131471
/// Probably will never become stable.
15141472
pub fn nontemporal_store<T>(ptr: *mut T, val: T);

src/libcore/ptr.rs

+21-10
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,7 @@ impl<T: ?Sized> *const T {
14781478
panic!("align_offset: align is not a power-of-two");
14791479
}
14801480
unsafe {
1481-
intrinsics::align_offset(self, align)
1481+
align_offset(self, align)
14821482
}
14831483
}
14841484

@@ -2543,7 +2543,7 @@ impl<T: ?Sized> *mut T {
25432543
panic!("align_offset: align is not a power-of-two");
25442544
}
25452545
unsafe {
2546-
intrinsics::align_offset(self, align)
2546+
align_offset(self, align)
25472547
}
25482548
}
25492549

@@ -2565,8 +2565,6 @@ impl<T: ?Sized> *mut T {
25652565
/// Calculate offset (in terms of elements of `stride` stride) that has to be applied
25662566
/// to pointer `p` so that pointer `p` would get aligned to `a`.
25672567
///
2568-
/// This is an implementation of the `align_offset` intrinsic for the case where `stride > 1`.
2569-
///
25702568
/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic.
25712569
/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated
25722570
/// constants.
@@ -2578,7 +2576,7 @@ impl<T: ?Sized> *mut T {
25782576
/// Any questions go to @nagisa.
25792577
#[lang="align_offset"]
25802578
#[cfg(not(stage0))]
2581-
unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize {
2579+
pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
25822580
/// Calculate multiplicative modular inverse of `x` modulo `m`.
25832581
///
25842582
/// This implementation is tailored for align_offset and has following preconditions:
@@ -2587,12 +2585,13 @@ unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize {
25872585
/// * `x < m`; (if `x ≥ m`, pass in `x % m` instead)
25882586
///
25892587
/// Implementation of this function shall not panic. Ever.
2588+
#[inline]
25902589
fn mod_inv(x: usize, m: usize) -> usize {
25912590
/// Multiplicative modular inverse table modulo 2⁴ = 16.
25922591
///
25932592
/// Note, that this table does not contain values where inverse does not exist (i.e. for
25942593
/// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.)
2595-
static INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
2594+
const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
25962595
/// Modulo for which the `INV_TABLE_MOD_16` is intended.
25972596
const INV_TABLE_MOD: usize = 16;
25982597
/// INV_TABLE_MOD²
@@ -2627,18 +2626,30 @@ unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize {
26272626
}
26282627
}
26292628

2629+
let stride = ::mem::size_of::<T>();
26302630
let a_minus_one = a.wrapping_sub(1);
26312631
let pmoda = p as usize & a_minus_one;
2632-
let smoda = stride & a_minus_one;
2633-
// a is power-of-two so cannot be 0. stride = 0 is handled by the intrinsic.
2634-
let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a));
2635-
let gcd = 1usize << gcdpow;
26362632

26372633
if pmoda == 0 {
26382634
// Already aligned. Yay!
26392635
return 0;
26402636
}
26412637

2638+
if stride <= 1 {
2639+
return if stride == 0 {
2640+
// If the pointer is not aligned, and the element is zero-sized, then no amount of
2641+
// elements will ever align the pointer.
2642+
!0
2643+
} else {
2644+
a.wrapping_sub(pmoda)
2645+
};
2646+
}
2647+
2648+
let smoda = stride & a_minus_one;
2649+
// a is power-of-two so cannot be 0. stride = 0 is handled above.
2650+
let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a));
2651+
let gcd = 1usize << gcdpow;
2652+
26422653
if gcd == 1 {
26432654
// This branch solves for the variable $o$ in following linear congruence equation:
26442655
//

src/libcore/slice/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1794,8 +1794,11 @@ impl<T> [T] {
17941794
// handle ZSTs specially, which is – don't handle them at all.
17951795
return (self, &[], &[]);
17961796
}
1797+
1798+
// First, find at what point do we split between the first and 2nd slice. Easy with
1799+
// ptr.align_offset.
17971800
let ptr = self.as_ptr();
1798-
let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::<U>());
1801+
let offset = ::ptr::align_offset(ptr, ::mem::align_of::<U>());
17991802
if offset > self.len() {
18001803
return (self, &[], &[]);
18011804
} else {
@@ -1848,7 +1851,7 @@ impl<T> [T] {
18481851
// First, find at what point do we split between the first and 2nd slice. Easy with
18491852
// ptr.align_offset.
18501853
let ptr = self.as_ptr();
1851-
let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::<U>());
1854+
let offset = ::ptr::align_offset(ptr, ::mem::align_of::<U>());
18521855
if offset > self.len() {
18531856
return (self, &mut [], &mut []);
18541857
} else {

src/librustc_codegen_llvm/intrinsic.rs

-26
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use type_of::LayoutLlvmExt;
2525
use rustc::ty::{self, Ty};
2626
use rustc::ty::layout::{HasDataLayout, LayoutOf};
2727
use rustc::hir;
28-
use rustc::middle::lang_items::AlignOffsetLangItem;
2928
use syntax::ast;
3029
use syntax::symbol::Symbol;
3130
use builder::Builder;
@@ -390,31 +389,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
390389
args[0].deref(bx.cx).codegen_get_discr(bx, ret_ty)
391390
}
392391

393-
"align_offset" => {
394-
let (ptr, align) = (args[0].immediate(), args[1].immediate());
395-
let stride_of_t = bx.cx.layout_of(substs.type_at(0)).size_and_align().0.bytes();
396-
let stride = C_usize(bx.cx, stride_of_t);
397-
let zero = C_null(bx.cx.isize_ty);
398-
let max = C_int(cx.isize_ty, -1); // -1isize (wherein I cheat horribly to make !0usize)
399-
400-
if stride_of_t <= 1 {
401-
// offset = ptr as usize % align => offset = ptr as usize & (align - 1)
402-
let modmask = bx.sub(align, C_usize(bx.cx, 1));
403-
let offset = bx.and(bx.ptrtoint(ptr, bx.cx.isize_ty), modmask);
404-
let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
405-
// if offset == 0 { 0 } else { if stride_of_t == 1 { align - offset } else { !0 } }
406-
bx.select(is_zero, zero, if stride_of_t == 1 {
407-
bx.sub(align, offset)
408-
} else {
409-
max
410-
})
411-
} else {
412-
let did = ::common::langcall(bx.tcx(), Some(span), "", AlignOffsetLangItem);
413-
let instance = ty::Instance::mono(bx.tcx(), did);
414-
let llfn = ::callee::get_fn(bx.cx, instance);
415-
bx.call(llfn, &[ptr, align, stride], None)
416-
}
417-
}
418392
name if name.starts_with("simd_") => {
419393
match generic_simd_intrinsic(bx, name,
420394
callee_ty,

src/librustc_typeck/check/intrinsic.rs

-4
Original file line numberDiff line numberDiff line change
@@ -314,10 +314,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
314314
(0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
315315
}
316316

317-
"align_offset" => {
318-
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.types.usize], tcx.types.usize)
319-
},
320-
321317
"nontemporal_store" => {
322318
(1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil())
323319
}

0 commit comments

Comments
 (0)